diff options
Diffstat (limited to 'editeng/source/misc')
-rw-r--r-- | editeng/source/misc/SvXMLAutoCorrectExport.cxx | 117 | ||||
-rw-r--r-- | editeng/source/misc/SvXMLAutoCorrectExport.hxx | 75 | ||||
-rw-r--r-- | editeng/source/misc/SvXMLAutoCorrectImport.cxx | 266 | ||||
-rw-r--r-- | editeng/source/misc/SvXMLAutoCorrectImport.hxx | 148 | ||||
-rw-r--r-- | editeng/source/misc/acorrcfg.cxx | 675 | ||||
-rwxr-xr-x | editeng/source/misc/edtdlg.cxx | 43 | ||||
-rw-r--r-- | editeng/source/misc/forbiddencharacterstable.cxx | 92 | ||||
-rw-r--r-- | editeng/source/misc/hangulhanja.cxx | 1171 | ||||
-rw-r--r-- | editeng/source/misc/lingu.src | 104 | ||||
-rw-r--r-- | editeng/source/misc/makefile.mk | 71 | ||||
-rw-r--r-- | editeng/source/misc/splwrap.cxx | 632 | ||||
-rw-r--r-- | editeng/source/misc/svxacorr.cxx | 2788 | ||||
-rw-r--r-- | editeng/source/misc/swafopt.cxx | 158 | ||||
-rw-r--r-- | editeng/source/misc/txtrange.cxx | 719 | ||||
-rwxr-xr-x | editeng/source/misc/unolingu.cxx | 1377 |
15 files changed, 8436 insertions, 0 deletions
diff --git a/editeng/source/misc/SvXMLAutoCorrectExport.cxx b/editeng/source/misc/SvXMLAutoCorrectExport.cxx new file mode 100644 index 000000000000..5557f850df1e --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectExport.cxx @@ -0,0 +1,117 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <SvXMLAutoCorrectExport.hxx> +#define _SVSTDARR_STRINGSISORTDTOR +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::rtl; + +// #110680# +SvXMLAutoCorrectExport::SvXMLAutoCorrectExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvxAutocorrWordList * pNewAutocorr_List, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler) +: SvXMLExport( xServiceFactory, rFileName, rHandler ), + pAutocorr_List( pNewAutocorr_List ) +{ + _GetNamespaceMap().Add( GetXMLToken ( XML_NP_BLOCK_LIST), + GetXMLToken ( XML_N_BLOCK_LIST ), + XML_NAMESPACE_BLOCKLIST ); +} + +sal_uInt32 SvXMLAutoCorrectExport::exportDoc(enum XMLTokenEnum /*eClass*/) +{ + GetDocHandler()->startDocument(); + + AddAttribute ( XML_NAMESPACE_NONE, + _GetNamespaceMap().GetAttrNameByKey ( XML_NAMESPACE_BLOCKLIST ), + _GetNamespaceMap().GetNameByKey ( XML_NAMESPACE_BLOCKLIST ) ); + { + SvXMLElementExport aRoot (*this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK_LIST, sal_True, sal_True); + sal_uInt16 nBlocks= pAutocorr_List->Count(); + for ( sal_uInt16 i = 0; i < nBlocks; i++) + { + SvxAutocorrWord* p = pAutocorr_List->GetObject(i); + + AddAttribute( XML_NAMESPACE_BLOCKLIST, + XML_ABBREVIATED_NAME, + OUString(p->GetShort())); + AddAttribute( XML_NAMESPACE_BLOCKLIST, + XML_NAME, + OUString(p->IsTextOnly() ? p->GetLong() : p->GetShort())); + + SvXMLElementExport aBlock( *this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK, sal_True, sal_True); + } + } + GetDocHandler()->endDocument(); + return 0; +} + +// #110680# +SvXMLExceptionListExport::SvXMLExceptionListExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvStringsISortDtor &rNewList, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler) +: SvXMLExport( xServiceFactory, rFileName, rHandler ), + rList( rNewList ) +{ + _GetNamespaceMap().Add( GetXMLToken ( XML_NP_BLOCK_LIST ), + GetXMLToken ( XML_N_BLOCK_LIST ), + XML_NAMESPACE_BLOCKLIST ); +} + +sal_uInt32 SvXMLExceptionListExport::exportDoc(enum XMLTokenEnum /*eClass*/) +{ + GetDocHandler()->startDocument(); + + AddAttribute ( XML_NAMESPACE_NONE, + _GetNamespaceMap().GetAttrNameByKey ( XML_NAMESPACE_BLOCKLIST ), + _GetNamespaceMap().GetNameByKey ( XML_NAMESPACE_BLOCKLIST ) ); + { + SvXMLElementExport aRoot (*this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK_LIST, sal_True, sal_True); + sal_uInt16 nBlocks= rList.Count(); + for ( sal_uInt16 i = 0; i < nBlocks; i++) + { + AddAttribute( XML_NAMESPACE_BLOCKLIST, + XML_ABBREVIATED_NAME, + OUString( *rList[i] ) ); + SvXMLElementExport aBlock( *this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK, sal_True, sal_True); + } + } + GetDocHandler()->endDocument(); + return 0; +} diff --git a/editeng/source/misc/SvXMLAutoCorrectExport.hxx b/editeng/source/misc/SvXMLAutoCorrectExport.hxx new file mode 100644 index 000000000000..28058a39c8da --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectExport.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SV_XMLAUTOCORRECTEXPORT_HXX +#define _SV_XMLAUTOCORRECTEXPORT_HXX + +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <editeng/svxacorr.hxx> + +class SvXMLAutoCorrectExport : public SvXMLExport +{ +private: + const SvxAutocorrWordList *pAutocorr_List; +public: + // #110680# + SvXMLAutoCorrectExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvxAutocorrWordList * pNewAutocorr_List, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler); + + virtual ~SvXMLAutoCorrectExport ( void ) {} + sal_uInt32 exportDoc(enum ::xmloff::token::XMLTokenEnum eClass); + void _ExportAutoStyles() {} + void _ExportMasterStyles () {} + void _ExportContent() {} +}; + +class SvStringsISortDtor; + +class SvXMLExceptionListExport : public SvXMLExport +{ +private: + const SvStringsISortDtor & rList; +public: + // #110680# + SvXMLExceptionListExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvStringsISortDtor &rNewList, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler); + + virtual ~SvXMLExceptionListExport ( void ) {} + sal_uInt32 exportDoc(enum ::xmloff::token::XMLTokenEnum eClass); + void _ExportAutoStyles() {} + void _ExportMasterStyles () {} + void _ExportContent() {} +}; +#endif diff --git a/editeng/source/misc/SvXMLAutoCorrectImport.cxx b/editeng/source/misc/SvXMLAutoCorrectImport.cxx new file mode 100644 index 000000000000..65f4bbb11ddc --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectImport.cxx @@ -0,0 +1,266 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <SvXMLAutoCorrectImport.hxx> +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif + +#define _SVSTDARR_STRINGSISORTDTOR +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::rtl; + + +static OUString sBlockList ( RTL_CONSTASCII_USTRINGPARAM ( "_block-list" ) ); + +// #110680# +SvXMLAutoCorrectImport::SvXMLAutoCorrectImport( + const uno::Reference< lang::XMultiServiceFactory > xServiceFactory, + SvxAutocorrWordList *pNewAutocorr_List, + SvxAutoCorrect &rNewAutoCorrect, + const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& rNewStorage) +: SvXMLImport( xServiceFactory ), + pAutocorr_List (pNewAutocorr_List), + rAutoCorrect ( rNewAutoCorrect ), + xStorage ( rNewStorage ) +{ + GetNamespaceMap().Add( + sBlockList, + GetXMLToken ( XML_N_BLOCK_LIST), + XML_NAMESPACE_BLOCKLIST ); +} + +SvXMLAutoCorrectImport::~SvXMLAutoCorrectImport ( void ) throw () +{ +} + +SvXMLImportContext *SvXMLAutoCorrectImport::CreateContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if( XML_NAMESPACE_BLOCKLIST == nPrefix && + IsXMLToken ( rLocalName, XML_BLOCK_LIST ) ) + pContext = new SvXMLWordListContext( *this, nPrefix, rLocalName, xAttrList ); + else + pContext = SvXMLImport::CreateContext( nPrefix, rLocalName, xAttrList ); + return pContext; +} + +SvXMLWordListContext::SvXMLWordListContext( + SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & /*xAttrList*/ ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ +} + +SvXMLImportContext *SvXMLWordListContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if (nPrefix == XML_NAMESPACE_BLOCKLIST && + IsXMLToken ( rLocalName, XML_BLOCK ) ) + pContext = new SvXMLWordContext (rLocalRef, nPrefix, rLocalName, xAttrList); + else + pContext = new SvXMLImportContext( rLocalRef, nPrefix, rLocalName); + return pContext; +} +SvXMLWordListContext::~SvXMLWordListContext ( void ) +{ +} + +SvXMLWordContext::SvXMLWordContext( + SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & xAttrList ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ + String sRight, sWrong; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + + for (sal_Int16 i=0; i < nAttrCount; i++) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName); + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + if (XML_NAMESPACE_BLOCKLIST == nAttrPrefix) + { + if ( IsXMLToken ( aLocalName, XML_ABBREVIATED_NAME ) ) + { + sWrong = rAttrValue; + } + else if ( IsXMLToken ( aLocalName, XML_NAME ) ) + { + sRight = rAttrValue; + } + } + } + if (!sWrong.Len() || !sRight.Len() ) + return; + +// const International& rInter = Application::GetAppInternational(); +// BOOL bOnlyTxt = COMPARE_EQUAL != rInter.Compare( sRight, sWrong, INTN_COMPARE_IGNORECASE ); + BOOL bOnlyTxt = sRight != sWrong; + if( !bOnlyTxt ) + { + String sLongSave( sRight ); + if( !rLocalRef.rAutoCorrect.GetLongText( rLocalRef.xStorage, String(), sWrong, sRight ) && + sLongSave.Len() ) + { + sRight = sLongSave; + bOnlyTxt = TRUE; + } + } + SvxAutocorrWordPtr pNew = new SvxAutocorrWord( sWrong, sRight, bOnlyTxt ); + + if( !rLocalRef.pAutocorr_List->Insert( pNew ) ) + delete pNew; +} + +SvXMLWordContext::~SvXMLWordContext ( void ) +{ +} + +// #110680# +SvXMLExceptionListImport::SvXMLExceptionListImport( + const uno::Reference< lang::XMultiServiceFactory > xServiceFactory, + SvStringsISortDtor & rNewList ) +: SvXMLImport( xServiceFactory ), + rList (rNewList) +{ + GetNamespaceMap().Add( + sBlockList, + GetXMLToken ( XML_N_BLOCK_LIST), + XML_NAMESPACE_BLOCKLIST ); +} + +SvXMLExceptionListImport::~SvXMLExceptionListImport ( void ) throw () +{ +} + +SvXMLImportContext *SvXMLExceptionListImport::CreateContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if( XML_NAMESPACE_BLOCKLIST==nPrefix && + IsXMLToken ( rLocalName, XML_BLOCK_LIST ) ) + pContext = new SvXMLExceptionListContext( *this, nPrefix, rLocalName, xAttrList ); + else + pContext = SvXMLImport::CreateContext( nPrefix, rLocalName, xAttrList ); + return pContext; +} + +SvXMLExceptionListContext::SvXMLExceptionListContext( + SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & /* xAttrList */ ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ +} + +SvXMLImportContext *SvXMLExceptionListContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if (nPrefix == XML_NAMESPACE_BLOCKLIST && + IsXMLToken ( rLocalName, XML_BLOCK ) ) + pContext = new SvXMLExceptionContext (rLocalRef, nPrefix, rLocalName, xAttrList); + else + pContext = new SvXMLImportContext( rLocalRef, nPrefix, rLocalName); + return pContext; +} +SvXMLExceptionListContext::~SvXMLExceptionListContext ( void ) +{ +} + +SvXMLExceptionContext::SvXMLExceptionContext( + SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & xAttrList ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ + String sWord; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + + for (sal_Int16 i=0; i < nAttrCount; i++) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName); + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + if (XML_NAMESPACE_BLOCKLIST == nAttrPrefix) + { + if ( IsXMLToken ( aLocalName, XML_ABBREVIATED_NAME ) ) + { + sWord = rAttrValue; + } + } + } + if (!sWord.Len() ) + return; + + String * pNew = new String( sWord ); + + if( !rLocalRef.rList.Insert( pNew ) ) + delete pNew; +} + +SvXMLExceptionContext::~SvXMLExceptionContext ( void ) +{ +} diff --git a/editeng/source/misc/SvXMLAutoCorrectImport.hxx b/editeng/source/misc/SvXMLAutoCorrectImport.hxx new file mode 100644 index 000000000000..951507ee4f19 --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectImport.hxx @@ -0,0 +1,148 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SV_XMLAUTOCORRECTIMPORT_HXX +#define _SV_XMLAUTOCORRECTIMPORT_HXX + +#ifndef _SVSTOR_HXX +#include <sot/storage.hxx> +#endif +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <editeng/svxacorr.hxx> + +class SvXMLAutoCorrectImport : public SvXMLImport +{ +protected: + + // This method is called after the namespace map has been updated, but + // before a context for the current element has been pushed. + virtual SvXMLImportContext *CreateContext( sal_uInt16 nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); +public: + SvxAutocorrWordList *pAutocorr_List; + SvxAutoCorrect &rAutoCorrect; + com::sun::star::uno::Reference < com::sun::star::embed::XStorage > xStorage; + //SvStorageRef &rStorage; + + // #110680# + SvXMLAutoCorrectImport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + SvxAutocorrWordList *pNewAutocorr_List, + SvxAutoCorrect &rNewAutoCorrect, + const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& rNewStorage); + + ~SvXMLAutoCorrectImport ( void ) throw (); +}; + +class SvXMLWordListContext : public SvXMLImportContext +{ +private: + SvXMLAutoCorrectImport & rLocalRef; +public: + SvXMLWordListContext ( SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLWordListContext ( void ); +}; + +class SvXMLWordContext : public SvXMLImportContext +{ +private: + SvXMLAutoCorrectImport & rLocalRef; +public: + SvXMLWordContext ( SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLWordContext ( void ); +}; + + +class SvXMLExceptionListImport : public SvXMLImport +{ +protected: + + // This method is called after the namespace map has been updated, but + // before a context for the current element has been pushed. + virtual SvXMLImportContext *CreateContext( sal_uInt16 nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); +public: + SvStringsISortDtor &rList; + + // #110680# + SvXMLExceptionListImport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + SvStringsISortDtor & rNewList ); + + ~SvXMLExceptionListImport ( void ) throw (); +}; + +class SvXMLExceptionListContext : public SvXMLImportContext +{ +private: + SvXMLExceptionListImport & rLocalRef; +public: + SvXMLExceptionListContext ( SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLExceptionListContext ( void ); +}; + +class SvXMLExceptionContext : public SvXMLImportContext +{ +private: + SvXMLExceptionListImport & rLocalRef; +public: + SvXMLExceptionContext ( SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLExceptionContext ( void ); +}; + + +#endif diff --git a/editeng/source/misc/acorrcfg.cxx b/editeng/source/misc/acorrcfg.cxx new file mode 100644 index 000000000000..966a0876fa30 --- /dev/null +++ b/editeng/source/misc/acorrcfg.cxx @@ -0,0 +1,675 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/acorrcfg.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <unotools/pathoptions.hxx> +#include <svl/urihelper.hxx> + +#include <editeng/svxacorr.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +using namespace utl; +using namespace rtl; +using namespace com::sun::star::uno; + +#define C2U(cChar) OUString::createFromAscii(cChar) + +static SvxAutoCorrCfg* pAutoCorrCfg = 0; + +/*-------------------------------------------------------------------- + Beschreibung: Ctor Dtor + --------------------------------------------------------------------*/ + +SvxAutoCorrCfg::SvxAutoCorrCfg() : + aBaseConfig(*this), + aSwConfig(*this), + bFileRel(TRUE), + bNetRel(TRUE), + bAutoTextTip(TRUE), + bAutoTextPreview(FALSE), + bAutoFmtByInput(TRUE), + bSearchInAllCategories(FALSE) +{ + SvtPathOptions aPathOpt; + String sSharePath, sUserPath, sAutoPath( aPathOpt.GetAutoCorrectPath() ); + + String* pS = &sSharePath; + for( USHORT n = 0; n < 2; ++n, pS = &sUserPath ) + { + *pS = sAutoPath.GetToken( n, ';' ); + INetURLObject aPath( *pS ); + aPath.insertName( String::CreateFromAscii("acor") ); + *pS = aPath.GetMainURL(INetURLObject::DECODE_TO_IURI); + } + pAutoCorrect = new SvxAutoCorrect( sSharePath, sUserPath ); + + aBaseConfig.Load(sal_True); + aSwConfig.Load(sal_True); +} + +SvxAutoCorrCfg::~SvxAutoCorrCfg() +{ + delete pAutoCorrect; +} + +void SvxAutoCorrCfg::SetAutoCorrect( SvxAutoCorrect* pNew ) +{ + if( pNew && pNew != pAutoCorrect ) + { + if( pAutoCorrect->GetFlags() != pNew->GetFlags() ) + { + aBaseConfig.SetModified(); + aSwConfig.SetModified(); + } + delete pAutoCorrect; + pAutoCorrect = pNew; + } +} +/*-- 12.10.00 11:44:17--------------------------------------------------- + + -----------------------------------------------------------------------*/ +Sequence<OUString> SvxBaseAutoCorrCfg::GetPropertyNames() +{ + static const char* aPropNames[] = + { + "Exceptions/TwoCapitalsAtStart", // 0 + "Exceptions/CapitalAtStartSentence", // 1 + "UseReplacementTable", // 2 + "TwoCapitalsAtStart", // 3 + "CapitalAtStartSentence", // 4 + "ChangeUnderlineWeight", // 5 + "SetInetAttribute", // 6 + "ChangeOrdinalNumber", // 7 + "AddNonBreakingSpace", // 8 + "ChangeDash", // 9 + "RemoveDoubleSpaces", // 10 + "ReplaceSingleQuote", // 11 + "SingleQuoteAtStart", // 12 + "SingleQuoteAtEnd", // 13 + "ReplaceDoubleQuote", // 14 + "DoubleQuoteAtStart", // 15 + "DoubleQuoteAtEnd" // 16 + }; + const int nCount = 17; + Sequence<OUString> aNames(nCount); + OUString* pNames = aNames.getArray(); + for(int i = 0; i < nCount; i++) + pNames[i] = OUString::createFromAscii(aPropNames[i]); + return aNames; +} +/*-- 12.10.00 11:44:18--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxBaseAutoCorrCfg::Load(sal_Bool bInit) +{ + Sequence<OUString> aNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(aNames); + if(bInit) + EnableNotification(aNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed"); + if(aValues.getLength() == aNames.getLength()) + { + long nFlags = 0; // default alles aus + sal_Int32 nTemp = 0; + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + switch(nProp) + { + case 0: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= SaveWordCplSttLst; + break;//"Exceptions/TwoCapitalsAtStart", + case 1: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= SaveWordWrdSttLst; + break;//"Exceptions/CapitalAtStartSentence", + case 2: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= Autocorrect; + break;//"UseReplacementTable", + case 3: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= CptlSttWrd; + break;//"TwoCapitalsAtStart", + case 4: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= CptlSttSntnc; + break;//"CapitalAtStartSentence", + case 5: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgWeightUnderl; + break;//"ChangeUnderlineWeight", + case 6: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= SetINetAttr; + break;//"SetInetAttribute", + case 7: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgOrdinalNumber; + break;//"ChangeOrdinalNumber", + case 8: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= AddNonBrkSpace; + break;//"AddNonBreakingSpace" + case 9: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgToEnEmDash; + break;//"ChangeDash", + case 10: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= IgnoreDoubleSpace; + break;//"RemoveDoubleSpaces", + case 11: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgSglQuotes; + break;//"ReplaceSingleQuote", + case 12: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetStartSingleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"SingleQuoteAtStart", + case 13: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetEndSingleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"SingleQuoteAtEnd", + case 14: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgQuotes; + break;//"ReplaceDoubleQuote", + case 15: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetStartDoubleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"DoubleQuoteAtStart", + case 16: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetEndDoubleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"DoubleQuoteAtEnd" + } + } + } + if( nFlags ) + rParent.pAutoCorrect->SetAutoCorrFlag( nFlags, TRUE ); + rParent.pAutoCorrect->SetAutoCorrFlag( ( 0xffff & ~nFlags ), FALSE ); + + } +} +/*-- 12.10.00 11:44:19--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxBaseAutoCorrCfg::SvxBaseAutoCorrCfg(SvxAutoCorrCfg& rPar) : + utl::ConfigItem(C2U("Office.Common/AutoCorrect")), + rParent(rPar) +{ +} +/*-- 12.10.00 11:44:19--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxBaseAutoCorrCfg::~SvxBaseAutoCorrCfg() +{ +} +/*-- 12.10.00 11:44:20--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxBaseAutoCorrCfg::Commit() +{ + Sequence<OUString> aNames( GetPropertyNames() ); + + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + + const Type& rType = ::getBooleanCppuType(); + BOOL bVal; + const long nFlags = rParent.pAutoCorrect->GetFlags(); + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + switch(nProp) + { + case 0: + bVal = 0 != (nFlags & SaveWordCplSttLst); + pValues[nProp].setValue(&bVal, rType); + break;//"Exceptions/TwoCapitalsAtStart", + case 1: + bVal = 0 != (nFlags & SaveWordWrdSttLst); + pValues[nProp].setValue(&bVal, rType); + break;//"Exceptions/CapitalAtStartSentence", + case 2: + bVal = 0 != (nFlags & Autocorrect); + pValues[nProp].setValue(&bVal, rType); + break;//"UseReplacementTable", + case 3: + bVal = 0 != (nFlags & CptlSttWrd); + pValues[nProp].setValue(&bVal, rType); + break;//"TwoCapitalsAtStart", + case 4: + bVal = 0 != (nFlags & CptlSttSntnc); + pValues[nProp].setValue(&bVal, rType); + break;//"CapitalAtStartSentence", + case 5: + bVal = 0 != (nFlags & ChgWeightUnderl); + pValues[nProp].setValue(&bVal, rType); + break;//"ChangeUnderlineWeight", + case 6: + bVal = 0 != (nFlags & SetINetAttr); + pValues[nProp].setValue(&bVal, rType); + break;//"SetInetAttribute", + case 7: + bVal = 0 != (nFlags & ChgOrdinalNumber); + pValues[nProp].setValue(&bVal, rType); + break;//"ChangeOrdinalNumber", + case 8: + bVal = 0 != (nFlags & AddNonBrkSpace); + pValues[nProp].setValue(&bVal, rType); + break;//"AddNonBreakingSpace" + case 9: + bVal = 0 != (nFlags & ChgToEnEmDash); + pValues[nProp].setValue(&bVal, rType); + break;//"ChangeDash", + case 10: + bVal = 0 != (nFlags & IgnoreDoubleSpace); + pValues[nProp].setValue(&bVal, rType); + break;//"RemoveDoubleSpaces", + case 11: + bVal = 0 != (nFlags & ChgSglQuotes); + pValues[nProp].setValue(&bVal, rType); + break;//"ReplaceSingleQuote", + case 12: + pValues[nProp] <<= (sal_Int32)rParent.pAutoCorrect->GetStartSingleQuote(); + break;//"SingleQuoteAtStart", + case 13: + pValues[nProp] <<= (sal_Int32) rParent.pAutoCorrect->GetEndSingleQuote(); + break;//"SingleQuoteAtEnd", + case 14: + bVal = 0 != (nFlags & ChgQuotes); + pValues[nProp].setValue(&bVal, rType); + break;//"ReplaceDoubleQuote", + case 15: + pValues[nProp] <<= (sal_Int32) rParent.pAutoCorrect->GetStartDoubleQuote(); + break;//"DoubleQuoteAtStart", + case 16: + pValues[nProp] <<= (sal_Int32) rParent.pAutoCorrect->GetEndDoubleQuote(); + break;//"DoubleQuoteAtEnd" + } + } + PutProperties(aNames, aValues); +} +/*-- 12.10.00 11:44:21--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxBaseAutoCorrCfg::Notify( const Sequence<OUString>& /* aPropertyNames */) +{ + Load(sal_False); +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +Sequence<OUString> SvxSwAutoCorrCfg::GetPropertyNames() +{ + static const char* aPropNames[] = + { + "Text/FileLinks", // 0 + "Text/InternetLinks", // 1 + "Text/ShowPreview", // 2 + "Text/ShowToolTip", // 3 + "Text/SearchInAllCategories", // 4 + "Format/Option/UseReplacementTable", // 5 + "Format/Option/TwoCapitalsAtStart", // 6 + "Format/Option/CapitalAtStartSentence", // 7 + "Format/Option/ChangeUnderlineWeight", // 8 + "Format/Option/SetInetAttribute", // 9 + "Format/Option/ChangeOrdinalNumber", //10 + "Format/Option/AddNonBreakingSpace", //11 + "Format/Option/ChangeDash", //12 + "Format/Option/DelEmptyParagraphs", //13 + "Format/Option/ReplaceUserStyle", //14 + "Format/Option/ChangeToBullets/Enable", //15 + "Format/Option/ChangeToBullets/SpecialCharacter/Char", //16 + "Format/Option/ChangeToBullets/SpecialCharacter/Font", //17 + "Format/Option/ChangeToBullets/SpecialCharacter/FontFamily", //18 + "Format/Option/ChangeToBullets/SpecialCharacter/FontCharset", //19 + "Format/Option/ChangeToBullets/SpecialCharacter/FontPitch", //20 + "Format/Option/CombineParagraphs", //21 + "Format/Option/CombineValue", //22 + "Format/Option/DelSpacesAtStartEnd", //23 + "Format/Option/DelSpacesBetween", //24 + "Format/ByInput/Enable", //25 + "Format/ByInput/ChangeDash", //26 + "Format/ByInput/ApplyNumbering/Enable", //27 + "Format/ByInput/ChangeToBorders", //28 + "Format/ByInput/ChangeToTable", //29 + "Format/ByInput/ReplaceStyle", //30 + "Format/ByInput/DelSpacesAtStartEnd", //31 + "Format/ByInput/DelSpacesBetween", //32 + "Completion/Enable", //33 + "Completion/MinWordLen", //34 + "Completion/MaxListLen", //35 + "Completion/CollectWords", //36 + "Completion/EndlessList", //37 + "Completion/AppendBlank", //38 + "Completion/ShowAsTip", //39 + "Completion/AcceptKey", //40 + "Completion/KeepList", //41 + "Format/ByInput/ApplyNumbering/SpecialCharacter/Char", //42 + "Format/ByInput/ApplyNumbering/SpecialCharacter/Font", //43 + "Format/ByInput/ApplyNumbering/SpecialCharacter/FontFamily", //44 + "Format/ByInput/ApplyNumbering/SpecialCharacter/FontCharset", //45 + "Format/ByInput/ApplyNumbering/SpecialCharacter/FontPitch" //46 + }; + const int nCount = 47; + Sequence<OUString> aNames(nCount); + OUString* pNames = aNames.getArray(); + for(int i = 0; i < nCount; i++) + pNames[i] = OUString::createFromAscii(aPropNames[i]); + return aNames; +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxSwAutoCorrCfg::Load(sal_Bool bInit) +{ + Sequence<OUString> aNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(aNames); + if(bInit) + EnableNotification(aNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed"); + if(aValues.getLength() == aNames.getLength()) + { + SvxSwAutoFmtFlags& rSwFlags = rParent.pAutoCorrect->GetSwFlags(); + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + switch(nProp) + { + case 0: rParent.bFileRel = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/FileLinks", + case 1: rParent.bNetRel = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/InternetLinks", + case 2: rParent.bAutoTextPreview = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/ShowPreview", + case 3: rParent.bAutoTextTip = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/ShowToolTip", + case 4: rParent.bSearchInAllCategories = *(sal_Bool*)pValues[nProp].getValue(); break; //"Text/SearchInAllCategories" + case 5: rSwFlags.bAutoCorrect = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/UseReplacementTable", + case 6: rSwFlags.bCptlSttSntnc = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/TwoCapitalsAtStart", + case 7: rSwFlags.bCptlSttWrd = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/CapitalAtStartSentence", + case 8: rSwFlags.bChgWeightUnderl = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeUnderlineWeight", + case 9: rSwFlags.bSetINetAttr = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/SetInetAttribute", + case 10: rSwFlags.bChgOrdinalNumber = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeOrdinalNumber", + case 11: rSwFlags.bAddNonBrkSpace = *(sal_Bool*)pValues[nProp].getValue( ); break; // "Format/Option/AddNonBreakingSpace", +// it doesn't exist here - the common flags are used for that -> LM +// case 12: rSwFlags.bChgToEnEmDash = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeDash", + case 13: rSwFlags.bDelEmptyNode = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/DelEmptyParagraphs", + case 14: rSwFlags.bChgUserColl = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ReplaceUserStyle", + case 15: rSwFlags.bChgEnumNum = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeToBullets/Enable", + case 16: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.cBullet = + sal::static_int_cast< sal_Unicode >(nVal); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Char", + case 17: + { + OUString sTemp; pValues[nProp] >>= sTemp; + rSwFlags.aBulletFont.SetName(sTemp); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Font", + case 18: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aBulletFont.SetFamily(FontFamily(nVal)); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontFamily", + case 19: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aBulletFont.SetCharSet(CharSet(nVal)); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontCharset", + case 20: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aBulletFont.SetPitch(FontPitch(nVal)); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontPitch", + case 21: rSwFlags.bRightMargin = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/CombineParagraphs", + case 22: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nRightMargin = + sal::static_int_cast< BYTE >(nVal); + } + break; // "Format/Option/CombineValue", + case 23: rSwFlags.bAFmtDelSpacesAtSttEnd = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/DelSpacesAtStartEnd", + case 24: rSwFlags.bAFmtDelSpacesBetweenLines = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/DelSpacesBetween", + case 25: rParent.bAutoFmtByInput = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/Enable", + case 26: rSwFlags.bChgToEnEmDash = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ChangeDash", + case 27: rSwFlags.bSetNumRule = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ApplyNumbering/Enable", + case 28: rSwFlags.bSetBorder = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ChangeToBorders", + case 29: rSwFlags.bCreateTable = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ChangeToTable", + case 30: rSwFlags.bReplaceStyles = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ReplaceStyle", + case 31: rSwFlags.bAFmtByInpDelSpacesAtSttEnd = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/DelSpacesAtStartEnd", + case 32: rSwFlags.bAFmtByInpDelSpacesBetweenLines = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/DelSpacesBetween", + case 33: rSwFlags.bAutoCompleteWords = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/Enable", + case 34: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nAutoCmpltWordLen = + sal::static_int_cast< USHORT >(nVal); + } + break; // "Completion/MinWordLen", + case 35: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nAutoCmpltListLen = + sal::static_int_cast< USHORT >(nVal); + } + break; // "Completion/MaxListLen", + case 36: rSwFlags.bAutoCmpltCollectWords = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/CollectWords", + case 37: rSwFlags.bAutoCmpltEndless = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/EndlessList", + case 38: rSwFlags.bAutoCmpltAppendBlanc = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/AppendBlank", + case 39: rSwFlags.bAutoCmpltShowAsTip = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/ShowAsTip", + case 40: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nAutoCmpltExpandKey = + sal::static_int_cast< USHORT >(nVal); + } + break; // "Completion/AcceptKey" + case 41 :rSwFlags.bAutoCmpltKeepList = *(sal_Bool*)pValues[nProp].getValue(); break;//"Completion/KeepList" + case 42 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.cByInputBullet = + sal::static_int_cast< sal_Unicode >(nVal); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Char", + case 43 : + { + OUString sTemp; pValues[nProp] >>= sTemp; + rSwFlags.aByInputBulletFont.SetName(sTemp); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Font", + case 44 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aByInputBulletFont.SetFamily(FontFamily(nVal)); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontFamily", + case 45 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aByInputBulletFont.SetCharSet(CharSet(nVal)); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontCharset", + case 46 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aByInputBulletFont.SetPitch(FontPitch(nVal)); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontPitch", + } + } + } + } +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxSwAutoCorrCfg::SvxSwAutoCorrCfg(SvxAutoCorrCfg& rPar) : + utl::ConfigItem(C2U("Office.Writer/AutoFunction")), + rParent(rPar) +{ +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxSwAutoCorrCfg::~SvxSwAutoCorrCfg() +{ +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxSwAutoCorrCfg::Commit() +{ + Sequence<OUString> aNames = GetPropertyNames(); + + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + + const Type& rType = ::getBooleanCppuType(); + BOOL bVal; + SvxSwAutoFmtFlags& rSwFlags = rParent.pAutoCorrect->GetSwFlags(); + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + switch(nProp) + { + case 0: pValues[nProp].setValue(&rParent.bFileRel, rType); break; // "Text/FileLinks", + case 1: pValues[nProp].setValue(&rParent.bNetRel, rType); break; // "Text/InternetLinks", + case 2: pValues[nProp].setValue(&rParent.bAutoTextPreview, rType); break; // "Text/ShowPreview", + case 3: pValues[nProp].setValue(&rParent.bAutoTextTip, rType); break; // "Text/ShowToolTip", + case 4: pValues[nProp].setValue(&rParent.bSearchInAllCategories, rType );break; //"Text/SearchInAllCategories" + case 5: bVal = rSwFlags.bAutoCorrect; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/UseReplacementTable", + case 6: bVal = rSwFlags.bCptlSttSntnc; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/TwoCapitalsAtStart", + case 7: bVal = rSwFlags.bCptlSttWrd; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/CapitalAtStartSentence", + case 8: bVal = rSwFlags.bChgWeightUnderl; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ChangeUnderlineWeight", + case 9: bVal = rSwFlags.bSetINetAttr; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/SetInetAttribute", + case 10: bVal = rSwFlags.bChgOrdinalNumber; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ChangeOrdinalNumber", + case 11: bVal = rSwFlags.bAddNonBrkSpace; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/AddNonBreakingSpace", +// it doesn't exist here - the common flags are used for that -> LM + case 12: + bVal = sal_True; pValues[nProp].setValue(&bVal, rType); + break; // "Format/Option/ChangeDash", + case 13: bVal = rSwFlags.bDelEmptyNode; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/DelEmptyParagraphs", + case 14: bVal = rSwFlags.bChgUserColl; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ReplaceUserStyle", + case 15: bVal = rSwFlags.bChgEnumNum; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ChangeToBullets/Enable", + case 16: + pValues[nProp] <<= (sal_Int32)rSwFlags.cBullet; + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Char", + case 17: + pValues[nProp] <<= OUString(rSwFlags.aBulletFont.GetName()); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Font", + case 18: + pValues[nProp] <<= (sal_Int32)rSwFlags.aBulletFont.GetFamily(); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontFamily", + case 19: + pValues[nProp] <<= (sal_Int32)rSwFlags.aBulletFont.GetCharSet(); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontCharset", + case 20: + pValues[nProp] <<= (sal_Int32)rSwFlags.aBulletFont.GetPitch(); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontPitch", + case 21: bVal = rSwFlags.bRightMargin; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/CombineParagraphs", + case 22: + pValues[nProp] <<= (sal_Int32)rSwFlags.nRightMargin; + break; // "Format/Option/CombineValue", + case 23: bVal = rSwFlags.bAFmtDelSpacesAtSttEnd; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/DelSpacesAtStartEnd", + case 24: bVal = rSwFlags.bAFmtDelSpacesBetweenLines; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/DelSpacesBetween", + case 25: bVal = rParent.bAutoFmtByInput; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/Enable", + case 26: bVal = rSwFlags.bChgToEnEmDash; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ChangeDash", + case 27: bVal = rSwFlags.bSetNumRule; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ApplyNumbering/Enable", + case 28: bVal = rSwFlags.bSetBorder; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ChangeToBorders", + case 29: bVal = rSwFlags.bCreateTable; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ChangeToTable", + case 30: bVal = rSwFlags.bReplaceStyles; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ReplaceStyle", + case 31: bVal = rSwFlags.bAFmtByInpDelSpacesAtSttEnd; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/DelSpacesAtStartEnd", + case 32: bVal = rSwFlags.bAFmtByInpDelSpacesBetweenLines; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/DelSpacesBetween", + case 33: bVal = rSwFlags.bAutoCompleteWords; pValues[nProp].setValue(&bVal, rType); break; // "Completion/Enable", + case 34: + pValues[nProp] <<= (sal_Int32)rSwFlags.nAutoCmpltWordLen; + break; // "Completion/MinWordLen", + case 35: + pValues[nProp] <<= (sal_Int32)rSwFlags.nAutoCmpltListLen; + break; // "Completion/MaxListLen", + case 36: bVal = rSwFlags.bAutoCmpltCollectWords; pValues[nProp].setValue(&bVal, rType); break; // "Completion/CollectWords", + case 37: bVal = rSwFlags.bAutoCmpltEndless; pValues[nProp].setValue(&bVal, rType); break; // "Completion/EndlessList", + case 38: bVal = rSwFlags.bAutoCmpltAppendBlanc; pValues[nProp].setValue(&bVal, rType); break; // "Completion/AppendBlank", + case 39: bVal = rSwFlags.bAutoCmpltShowAsTip; pValues[nProp].setValue(&bVal, rType); break; // "Completion/ShowAsTip", + case 40: + pValues[nProp] <<= (sal_Int32)rSwFlags.nAutoCmpltExpandKey; + break; // "Completion/AcceptKey" + case 41 :bVal = rSwFlags.bAutoCmpltKeepList; pValues[nProp].setValue(&bVal, rType); break;// "Completion/KeepList" + case 42 : + pValues[nProp] <<= (sal_Int32)rSwFlags.cByInputBullet; + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Char", + case 43 : + pValues[nProp] <<= OUString(rSwFlags.aByInputBulletFont.GetName()); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Font", + case 44 : + pValues[nProp] <<= (sal_Int32)rSwFlags.aByInputBulletFont.GetFamily(); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontFamily", + case 45 : + pValues[nProp] <<= (sal_Int32)rSwFlags.aByInputBulletFont.GetCharSet(); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontCharset", + case 46 : + pValues[nProp] <<= (sal_Int32)rSwFlags.aByInputBulletFont.GetPitch(); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontPitch", + } + } + PutProperties(aNames, aValues); +} +/*-- 12.10.00 11:51:49--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxSwAutoCorrCfg::Notify( const Sequence<OUString>& /* aPropertyNames */ ) +{ + Load(sal_False); +} + +SvxAutoCorrCfg* SvxAutoCorrCfg::Get() +{ + if( !pAutoCorrCfg ) + pAutoCorrCfg = new SvxAutoCorrCfg; + return pAutoCorrCfg; +} diff --git a/editeng/source/misc/edtdlg.cxx b/editeng/source/misc/edtdlg.cxx new file mode 100755 index 000000000000..3a4e209f3d4f --- /dev/null +++ b/editeng/source/misc/edtdlg.cxx @@ -0,0 +1,43 @@ +/************************************************************************* + * + * 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: sfxdlg.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/edtdlg.hxx> + +EditAbstractDialogFactory* EditAbstractDialogFactory::Create() +{ + return dynamic_cast <EditAbstractDialogFactory*>( VclAbstractDialogFactory::Create() ); +} + +EditAbstractDialogFactory::~EditAbstractDialogFactory() +{ +} diff --git a/editeng/source/misc/forbiddencharacterstable.cxx b/editeng/source/misc/forbiddencharacterstable.cxx new file mode 100644 index 000000000000..52b439838ce0 --- /dev/null +++ b/editeng/source/misc/forbiddencharacterstable.cxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/forbiddencharacterstable.hxx> + +#include <unotools/localedatawrapper.hxx> +#include <editeng/unolingu.hxx> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +SvxForbiddenCharactersTable::SvxForbiddenCharactersTable( ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF, USHORT nISize, USHORT nGrow ) + : SvxForbiddenCharactersTableImpl( nISize, nGrow ) +{ + mxMSF = xMSF; +} + + +SvxForbiddenCharactersTable::~SvxForbiddenCharactersTable() +{ + for ( ULONG n = Count(); n; ) + delete GetObject( --n ); +} + + + +const com::sun::star::i18n::ForbiddenCharacters* SvxForbiddenCharactersTable::GetForbiddenCharacters( USHORT nLanguage, BOOL bGetDefault ) const +{ + ForbiddenCharactersInfo* pInf = Get( nLanguage ); + if ( !pInf && bGetDefault && mxMSF.is() ) + { + const SvxForbiddenCharactersTableImpl *pConstImpl = dynamic_cast<const SvxForbiddenCharactersTableImpl*>(this); + SvxForbiddenCharactersTableImpl* pImpl = const_cast<SvxForbiddenCharactersTableImpl*>(pConstImpl); + pInf = new ForbiddenCharactersInfo; + pImpl->Insert( nLanguage, pInf ); + + pInf->bTemporary = TRUE; + LocaleDataWrapper aWrapper( mxMSF, SvxCreateLocale( nLanguage ) ); + pInf->aForbiddenChars = aWrapper.getForbiddenCharacters(); + } + return pInf ? &pInf->aForbiddenChars : NULL; +} + + + +void SvxForbiddenCharactersTable::SetForbiddenCharacters( USHORT nLanguage, const com::sun::star::i18n::ForbiddenCharacters& rForbiddenChars ) +{ + ForbiddenCharactersInfo* pInf = Get( nLanguage ); + if ( !pInf ) + { + pInf = new ForbiddenCharactersInfo; + Insert( nLanguage, pInf ); + } + pInf->bTemporary = FALSE; + pInf->aForbiddenChars = rForbiddenChars; +} + +void SvxForbiddenCharactersTable::ClearForbiddenCharacters( USHORT nLanguage ) +{ + ForbiddenCharactersInfo* pInf = Get( nLanguage ); + if ( pInf ) + { + Remove( nLanguage ); + delete pInf; + } +} diff --git a/editeng/source/misc/hangulhanja.cxx b/editeng/source/misc/hangulhanja.cxx new file mode 100644 index 000000000000..378ffb705300 --- /dev/null +++ b/editeng/source/misc/hangulhanja.cxx @@ -0,0 +1,1171 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <editeng/hangulhanja.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/button.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/linguprops.hxx> + +#include <set> +#include <map> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/i18n/UnicodeScript.hpp> +#include <com/sun/star/i18n/XTextConversion.hpp> +#include <com/sun/star/i18n/XExtendedTextConversion.hpp> +#include <com/sun/star/i18n/TextConversionType.hpp> +#include <com/sun/star/i18n/TextConversionOption.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <vcl/stdtext.hxx> +#include <unotools/charclass.hxx> + +#include <editeng/edtdlg.hxx> +#include <editeng/editrids.hrc> +#include <editeng/unolingu.hxx> + +#define HHC HangulHanjaConversion + +//............................................................................. +namespace editeng +{ +//............................................................................. + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::i18n; + using namespace ::com::sun::star::i18n::TextConversionOption; + using namespace ::com::sun::star::i18n::TextConversionType; + using namespace ::com::sun::star::lang; +/* + using HangulHanjaConversion::ReplacementAction; + using HangulHanjaConversion::eExchange; + using HangulHanjaConversion::eReplacementBracketed; + using HangulHanjaConversion::eOriginalBracketed; + using HangulHanjaConversion::eReplacementAbove; + using HangulHanjaConversion::eOriginalAbove; + using HangulHanjaConversion::eReplacementBelow; + using HangulHanjaConversion::eOriginalBelow; + + using HangulHanjaConversion::eHangulToHanja; + using HangulHanjaConversion::eHanjaToHangul; + + using HangulHanjaConversion::eSimpleConversion; + using HangulHanjaConversion::eHangulBracketed; + using HangulHanjaConversion::eHanjaBracketed; + using HangulHanjaConversion::eRubyHanjaAbove; + using HangulHanjaConversion::eRubyHanjaBelow; + using HangulHanjaConversion::eRubyHangulAbove; + using HangulHanjaConversion::eRubyHangulBelow; + + using ::com::sun::star::i18n::TextConversionType::TO_HANJA; + using ::com::sun::star::i18n::TextConversionType::TO_HANGUL; + using ::com::sun::star::i18n::TextConversionOption::CHARACTER_BY_CHARACTER; + using ::com::sun::star::i18n::TextConversionOption::NONE; +*/ + //========================================================================= + //= HangulHanjaConversion_Impl + //========================================================================= + //using HangulHanjaConversion::ConversionFormat; + + class HangulHanjaConversion_Impl + { + private: + typedef ::std::set< ::rtl::OUString, ::std::less< ::rtl::OUString > > StringBag; + typedef ::std::map< ::rtl::OUString, ::rtl::OUString, ::std::less< ::rtl::OUString > > StringMap; + + private: + StringBag m_sIgnoreList; + StringMap m_aChangeList; + static StringMap m_aRecentlyUsedList; + + // general + AbstractHangulHanjaConversionDialog* //CHINA001 HangulHanjaConversionDialog* + m_pConversionDialog; // the dialog to display for user interaction + Window* m_pUIParent; // the parent window for any UI we raise + Reference< XMultiServiceFactory > + m_xORB; // the service factory to use + Reference< XTextConversion > + m_xConverter; // the text conversion service + Locale m_aSourceLocale; // the locale we're working with + + // additions for Chinese simplified / traditional conversion + HHC::ConversionType m_eConvType; // conversion type (Hangul/Hanja, simplified/traditional Chinese,...) + LanguageType m_nSourceLang; // just a 'copy' of m_aSourceLocale in order in order to + // save the applications from always converting to this + // type in their implementations + LanguageType m_nTargetLang; // target language of new replacement text + const Font* m_pTargetFont; // target font of new replacement text + sal_Int32 m_nConvOptions; // text conversion options (as used by 'getConversions') + sal_Bool m_bIsInteractive; // specifies if the conversion requires user interaction + // (and likeley a specialised dialog) or if it is to run + // automatically without any user interaction. + // True for Hangul / Hanja conversion + // False for Chinese simlified / traditional conversion + + HangulHanjaConversion* m_pAntiImpl; // our "anti-impl" instance + + // options + sal_Bool m_bByCharacter; // are we in "by character" mode currently? + HHC::ConversionFormat m_eConversionFormat; // the current format for the conversion + HHC::ConversionDirection m_ePrimaryConversionDirection; // the primary conversion direction + HHC::ConversionDirection m_eCurrentConversionDirection; // the primary conversion direction + + //options from Hangul/Hanja Options dialog (also saved to configuration) + bool m_bIgnorePostPositionalWord; + bool m_bShowRecentlyUsedFirst; + bool m_bAutoReplaceUnique; + + // state + ::rtl::OUString m_sCurrentPortion; // the text which we are currently working on + LanguageType m_nCurrentPortionLang; // language of m_sCurrentPortion found + sal_Int32 m_nCurrentStartIndex; // the start index within m_sCurrentPortion of the current convertible portion + sal_Int32 m_nCurrentEndIndex; // the end index (excluding) within m_sCurrentPortion of the current convertible portion + sal_Int32 m_nReplacementBaseIndex;// index which ReplaceUnit-calls need to be relative to + sal_Int32 m_nCurrentConversionOption; + sal_Int16 m_nCurrentConversionType; + Sequence< ::rtl::OUString > + m_aCurrentSuggestions; // the suggestions for the current unit + // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion) + sal_Bool m_bTryBothDirections; // specifies if other conversion directions should be tried when looking for convertible characters + + + public: + HangulHanjaConversion_Impl( + Window* _pUIParent, + const Reference< XMultiServiceFactory >& _rxORB, + const Locale& _rSourceLocale, + const Locale& _rTargetLocale, + const Font* _pTargetFont, + sal_Int32 _nConvOptions, + sal_Bool _bIsInteractive, + HangulHanjaConversion* _pAntiImpl ); + + public: + + static void SetUseSavedConversionDirectionState( sal_Bool bVal ); + + void DoDocumentConversion( ); + + inline sal_Bool IsByCharacter( ) const { return m_bByCharacter; } + + inline sal_Bool IsValid() const { return m_xConverter.is(); } + + inline LanguageType GetSourceLang() const { return m_nSourceLang; } + inline LanguageType GetTargetLang() const { return m_nTargetLang; } + inline const Font * GetTargetFont() const { return m_pTargetFont; } + inline sal_Int32 GetConvOptions() const { return m_nConvOptions; } + inline sal_Bool IsInteractive() const { return m_bIsInteractive; } + + protected: + void createDialog(); + + /** continue with the conversion, return <TRUE/> if and only if the complete conversion is done + @param _bRepeatCurrentUnit + if <TRUE/>, an implNextConvertible will be called initially to advance to the next convertible. + if <FALSE/>, the method will initially work with the current convertible unit + */ + sal_Bool ContinueConversion( bool _bRepeatCurrentUnit ); + + private: + DECL_LINK( OnOptionsChanged, void* ); + DECL_LINK( OnIgnore, void* ); + DECL_LINK( OnIgnoreAll, void* ); + DECL_LINK( OnChange, void* ); + DECL_LINK( OnChangeAll, void* ); + DECL_LINK( OnByCharClicked, CheckBox* ); + DECL_LINK( OnConversionTypeChanged, void* ); + DECL_LINK( OnFind, void* ); + + /** proceed, after the current convertible has been handled + + <p><b>Attention:</b> + When returning from this method, the dialog may have been deleted!</p> + + @param _bRepeatCurrentUnit + will be passed to the <member>ContinueConversion</member> call + */ + void implProceed( bool _bRepeatCurrentUnit ); + + // change the current convertible, and do _not_ proceed + void implChange( const ::rtl::OUString& _rChangeInto ); + + /** find the next convertible piece of text, with possibly advancing to the next portion + + @see HangulHanjaConversion::GetNextPortion + */ + sal_Bool implNextConvertible( bool _bRepeatUnit ); + + /** find the next convertible unit within the current portion + @param _bRepeatUnit + if <TRUE/>, the search will start at the beginning of the current unit, + if <FALSE/>, it will start at the end of the current unit + */ + bool implNextConvertibleUnit( const sal_Int32 _nStartAt ); + + /** retrieves the next portion, with setting the index members properly + @return + <TRUE/> if and only if there is a next portion + */ + bool implRetrieveNextPortion( ); + + /** determine the ConversionDirection for m_sCurrentPortion + @return + <FALSE/> if and only if something went wrong + */ + bool implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection ); + + /** member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and current dictionaries + + if _bAllowSearchNextConvertibleText is true _nStartAt is used as starting point to search the next + convertible text portion. This may result in changing of the member m_nCurrentStartIndex additionally. + + @return + <TRUE/> if Suggestions were found + */ + bool implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText=false, const sal_Int32 _nStartAt=-1 ); + + /** reads the options from Hangul/Hanja Options dialog that are saved to configuration + */ + void implReadOptionsFromConfiguration(); + + /** get the string currently considered to be replaced or ignored + */ + ::rtl::OUString GetCurrentUnit() const; + + /** read options from configuration, update suggestion list and dialog content + */ + void implUpdateData(); + + /** get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection + in case of switching the direction is allowed this can be triggered with parameter bSwitchDirection + */ + sal_Int16 implGetConversionType( bool bSwitchDirection=false ) const; + }; + + //========================================================================= + //= HangulHanjaConversion_Impl + //========================================================================= + //------------------------------------------------------------------------- + // static member initialization + HangulHanjaConversion_Impl::StringMap HangulHanjaConversion_Impl::m_aRecentlyUsedList = HangulHanjaConversion_Impl::StringMap(); + + //------------------------------------------------------------------------- + HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window* _pUIParent, + const Reference< XMultiServiceFactory >& _rxORB, + const Locale& _rSourceLocale, + const Locale& _rTargetLocale, + const Font* _pTargetFont, + sal_Int32 _nOptions, + sal_Bool _bIsInteractive, + HangulHanjaConversion* _pAntiImpl ) +: m_pConversionDialog( NULL ) +, m_pUIParent( _pUIParent ) +, m_xORB( _rxORB ) +, m_aSourceLocale( _rSourceLocale ) +, m_nSourceLang( SvxLocaleToLanguage( _rSourceLocale ) ) +, m_nTargetLang( SvxLocaleToLanguage( _rTargetLocale ) ) +, m_pTargetFont( _pTargetFont ) +, m_bIsInteractive( _bIsInteractive ) +, m_pAntiImpl( _pAntiImpl ) +, m_nCurrentPortionLang( LANGUAGE_NONE ) +, m_nCurrentStartIndex( 0 ) +, m_nCurrentEndIndex( 0 ) +, m_nReplacementBaseIndex( 0 ) +, m_nCurrentConversionOption( TextConversionOption::NONE ) +, m_nCurrentConversionType( -1 ) // not yet known +, m_bTryBothDirections( sal_True ) + { + implReadOptionsFromConfiguration(); + + DBG_ASSERT( m_xORB.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" ); + + // determine conversion type + if (m_nSourceLang == LANGUAGE_KOREAN && m_nTargetLang == LANGUAGE_KOREAN) + m_eConvType = HHC::eConvHangulHanja; + else if ( (m_nSourceLang == LANGUAGE_CHINESE_TRADITIONAL && m_nTargetLang == LANGUAGE_CHINESE_SIMPLIFIED) || + (m_nSourceLang == LANGUAGE_CHINESE_SIMPLIFIED && m_nTargetLang == LANGUAGE_CHINESE_TRADITIONAL) ) + m_eConvType = HHC::eConvSimplifiedTraditional; + else + { + DBG_ERROR( "failed to determine conversion type from languages" ); + } + + // set remaining conversion parameters to their default values + m_nConvOptions = _nOptions; + m_bByCharacter = 0 != (_nOptions & CHARACTER_BY_CHARACTER); + m_eConversionFormat = HHC::eSimpleConversion; + m_ePrimaryConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja + m_eCurrentConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja + + if ( m_xORB.is() ) + { + ::rtl::OUString sTextConversionService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.TextConversion" ) ); + m_xConverter = m_xConverter.query( m_xORB->createInstance( sTextConversionService ) ); + if ( !m_xConverter.is() ) + ShowServiceNotAvailableError( m_pUIParent, sTextConversionService, sal_True ); + } + + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::createDialog() + { + DBG_ASSERT( m_bIsInteractive, "createDialog when the conversion should not be interactive?" ); + if ( m_bIsInteractive && !m_pConversionDialog ) + { + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + if(pFact) + { + m_pConversionDialog = pFact->CreateHangulHanjaConversionDialog(m_pUIParent, m_ePrimaryConversionDirection ); + DBG_ASSERT(m_pConversionDialog, "Dialogdiet fail!");//CHINA001 + + m_pConversionDialog->EnableRubySupport( m_pAntiImpl->HasRubySupport() ); + + m_pConversionDialog->SetByCharacter( m_bByCharacter ); + m_pConversionDialog->SetConversionFormat( m_eConversionFormat ); + m_pConversionDialog->SetConversionDirectionState( m_bTryBothDirections, m_ePrimaryConversionDirection ); + + // the handlers + m_pConversionDialog->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnOptionsChanged ) ); + m_pConversionDialog->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnore ) ); + m_pConversionDialog->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnoreAll ) ); + m_pConversionDialog->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl, OnChange ) ); + m_pConversionDialog->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl, OnChangeAll ) ); + m_pConversionDialog->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl, OnByCharClicked ) ); + m_pConversionDialog->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnConversionTypeChanged ) ); + m_pConversionDialog->SetFindHdl( LINK( this, HangulHanjaConversion_Impl, OnFind ) ); + } + } + } + + //------------------------------------------------------------------------- + sal_Int16 HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection ) const + { + sal_Int16 nConversionType = -1; + if (m_eConvType == HHC::eConvHangulHanja) + nConversionType = HHC::eHangulToHanja == ( m_eCurrentConversionDirection && !bSwitchDirection ) ? TO_HANJA : TO_HANGUL; + else if (m_eConvType == HHC::eConvSimplifiedTraditional) + nConversionType = LANGUAGE_CHINESE_SIMPLIFIED == m_nTargetLang ? TO_SCHINESE : TO_TCHINESE; + DBG_ASSERT( nConversionType != -1, "unexpected conversion type" ); + return nConversionType; + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText, const sal_Int32 _nStartAt ) + { + // parameters for the converter + sal_Int32 nStartSearch = m_nCurrentStartIndex; + if( _bAllowSearchNextConvertibleText ) + nStartSearch = _nStartAt; + + sal_Int32 nLength = m_sCurrentPortion.getLength() - nStartSearch; + m_nCurrentConversionType = implGetConversionType(); + m_nCurrentConversionOption = IsByCharacter() ? CHARACTER_BY_CHARACTER : NONE; + if( m_bIgnorePostPositionalWord ) + m_nCurrentConversionOption = m_nCurrentConversionOption | IGNORE_POST_POSITIONAL_WORD; + + // no need to check both directions for chinese conversion (saves time) + if (m_eConvType == HHC::eConvSimplifiedTraditional) + m_bTryBothDirections = sal_False; + + sal_Bool bFoundAny = sal_True; + try + { + TextConversionResult aResult = m_xConverter->getConversions( + m_sCurrentPortion, + nStartSearch, + nLength, + m_aSourceLocale, + m_nCurrentConversionType, + m_nCurrentConversionOption + ); + sal_Bool bFoundPrimary = aResult.Boundary.startPos < aResult.Boundary.endPos; + bFoundAny = bFoundPrimary; + + if ( m_bTryBothDirections ) + { // see if we find another convertible when assuming the other direction + TextConversionResult aSecondResult = m_xConverter->getConversions( + m_sCurrentPortion, + nStartSearch, + nLength, + m_aSourceLocale, + implGetConversionType( true ), // switched! + m_nCurrentConversionOption + ); + if ( aSecondResult.Boundary.startPos < aSecondResult.Boundary.endPos ) + { // we indeed found such a convertible + + // in case the first attempt (with the original conversion direction) + // didn't find anything + if ( !bFoundPrimary + // or if the second location is _before_ the first one + || ( aSecondResult.Boundary.startPos < aResult.Boundary.startPos ) + ) + { + // then use the second finding + aResult = aSecondResult; + + // our current conversion direction changed now + m_eCurrentConversionDirection = ( HHC::eHangulToHanja == m_eCurrentConversionDirection ) + ? HHC::eHanjaToHangul : HHC::eHangulToHanja; + bFoundAny = sal_True; + } + } + } + + if( _bAllowSearchNextConvertibleText ) + { + //this might change the current position + m_aCurrentSuggestions = aResult.Candidates; + m_nCurrentStartIndex = aResult.Boundary.startPos; + m_nCurrentEndIndex = aResult.Boundary.endPos; + } + else + { + //the change of starting position is not allowed + if( m_nCurrentStartIndex == aResult.Boundary.startPos + && aResult.Boundary.endPos != aResult.Boundary.startPos ) + { + m_aCurrentSuggestions = aResult.Candidates; + m_nCurrentEndIndex = aResult.Boundary.endPos; + } + else + { + m_aCurrentSuggestions.realloc( 0 ); + if( m_sCurrentPortion.getLength() >= m_nCurrentStartIndex+1 ) + m_nCurrentEndIndex = m_nCurrentStartIndex+1; + } + } + + //put recently used string to front: + if( m_bShowRecentlyUsedFirst && m_aCurrentSuggestions.getLength()>1 ) + { + ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); + StringMap::const_iterator aRecentlyUsed = m_aRecentlyUsedList.find( sCurrentUnit ); + bool bUsedBefore = aRecentlyUsed != m_aRecentlyUsedList.end(); + if( bUsedBefore && m_aCurrentSuggestions[0] != aRecentlyUsed->second ) + { + sal_Int32 nCount = m_aCurrentSuggestions.getLength(); + Sequence< ::rtl::OUString > aTmp(nCount); + aTmp[0]=aRecentlyUsed->second; + sal_Int32 nDiff = 1; + for( sal_Int32 n=1; n<nCount; n++)//we had 0 already + { + if( nDiff && m_aCurrentSuggestions[n-nDiff]==aRecentlyUsed->second ) + nDiff=0; + aTmp[n]=m_aCurrentSuggestions[n-nDiff]; + } + m_aCurrentSuggestions = aTmp; + } + } + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" ); + + //!!! at least we want to move on in the text in order + //!!! to avoid an endless loop... + return false; + } + return bFoundAny; + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt ) + { + m_aCurrentSuggestions.realloc( 0 ); + + // ask the TextConversion service for the next convertible piece of text + + // get current values from dialog + if( m_eConvType == HHC::eConvHangulHanja && m_pConversionDialog ) + { + m_bTryBothDirections = m_pConversionDialog->GetUseBothDirections(); + HHC::ConversionDirection eDialogDirection = HHC::eHangulToHanja; + eDialogDirection = m_pConversionDialog->GetDirection( eDialogDirection ); + + if( !m_bTryBothDirections && eDialogDirection != m_eCurrentConversionDirection ) + { + m_eCurrentConversionDirection = eDialogDirection; + } + + // save curently used value for possible later use + m_pAntiImpl->m_bTryBothDirectionsSave = m_bTryBothDirections; + m_pAntiImpl->m_ePrimaryConversionDirectionSave = m_eCurrentConversionDirection; + } + + bool bFoundAny = implUpdateSuggestions( true, _nStartAt ); + + return bFoundAny && + (m_nCurrentStartIndex < m_sCurrentPortion.getLength()); + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implRetrieveNextPortion( ) + { + sal_Bool bAllowImplicitChanges = m_eConvType == HHC::eConvSimplifiedTraditional; + + m_sCurrentPortion = ::rtl::OUString(); + m_nCurrentPortionLang = LANGUAGE_NONE; + m_pAntiImpl->GetNextPortion( m_sCurrentPortion, m_nCurrentPortionLang, bAllowImplicitChanges ); + m_nReplacementBaseIndex = 0; + m_nCurrentStartIndex = m_nCurrentEndIndex = 0; + + bool bRet = 0 != m_sCurrentPortion.getLength(); + + if (m_eConvType == HHC::eConvHangulHanja && m_bTryBothDirections) + implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection ); + + return bRet; + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit ) + { + if ( _bRepeatUnit || ( m_nCurrentEndIndex < m_sCurrentPortion.getLength() ) ) + { + if ( implNextConvertibleUnit( + _bRepeatUnit + ? ( IsByCharacter() ? m_nCurrentStartIndex : m_nCurrentStartIndex ) + : m_nCurrentEndIndex + ) ) + return sal_True; + } + + // no convertible text in the current portion anymore + // -> advance to the next portion + do + { + // next portion + if ( implRetrieveNextPortion( ) ) + { // there is a next portion + // -> find the next convertible unit in the current portion + if ( implNextConvertibleUnit( 0 ) ) + return sal_True; + } + } + while ( m_sCurrentPortion.getLength() ); + + // no more portions + return sal_False; + } + + //------------------------------------------------------------------------- + ::rtl::OUString HangulHanjaConversion_Impl::GetCurrentUnit() const + { + DBG_ASSERT( m_nCurrentStartIndex < m_sCurrentPortion.getLength(), + "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" ); + DBG_ASSERT( m_nCurrentEndIndex <= m_sCurrentPortion.getLength(), + "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" ); + DBG_ASSERT( m_nCurrentStartIndex <= m_nCurrentEndIndex, + "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" ); + + ::rtl::OUString sCurrentUnit = m_sCurrentPortion.copy( m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex ); + return sCurrentUnit; + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit ) + { + sal_Bool bNeedUserInteraction = sal_False; // when we leave here, do we need user interaction? + sal_Bool bDocumentDone = sal_False; // did we already check the whole document? + + while ( !bDocumentDone && !bNeedUserInteraction && implNextConvertible( _bRepeatCurrentUnit ) ) + { + ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); + + // do we need to ignore it? + sal_Bool bAlwaysIgnoreThis = m_sIgnoreList.end() != m_sIgnoreList.find( sCurrentUnit ); + + // do we need to change it? + StringMap::const_iterator aChangeListPos = m_aChangeList.find( sCurrentUnit ); + sal_Bool bAlwaysChangeThis = m_aChangeList.end() != aChangeListPos; + + // do we automatically change this? + sal_Bool bAutoChange = m_bAutoReplaceUnique && m_aCurrentSuggestions.getLength() == 1; + + if (!m_bIsInteractive) + { + // silent conversion (e.g. for simplified/traditional Chinese)... + if(m_aCurrentSuggestions.getLength()>0) + implChange( m_aCurrentSuggestions.getConstArray()[0] ); + } + else if (bAutoChange) + { + implChange( m_aCurrentSuggestions.getConstArray()[0] ); + } + else if ( bAlwaysChangeThis ) + { + implChange( aChangeListPos->second ); + } + else if ( !bAlwaysIgnoreThis ) + { + // here we need to ask the user for what to do with the text + // for this, allow derivees to highlight the current text unit in a possible document view + m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex ); + + DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); + if( m_pConversionDialog ) + m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions ); + + // do not look for the next convertible: We have to wait for the user to interactivly + // decide what happens with the current convertible + bNeedUserInteraction = sal_True; + } + } + + /* + if ( bDocumentDone ) + return sal_True; // we explicitly know that the complete document is done + else if ( bNeedUserInteraction ) + return sal_False; // the doc is not done, we found a convertible, but need the user to decide + else + return sal_True; // we did not find a next convertible, so the document is implicitly done + */ + + return bDocumentDone || !bNeedUserInteraction; + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection ) + { + // - For eConvHangulHanja the direction is determined by + // the first encountered Korean character. + // - For eConvSimplifiedTraditional the conversion direction + // is already specified by the source language. + + bool bSuccess = true; + + if (m_eConvType == HHC::eConvHangulHanja) + { + bSuccess = false; + try + { + // get the break iterator service + ::rtl::OUString sBreakIteratorService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) ); + Reference< XInterface > xBI( m_xORB->createInstance( ::rtl::OUString( sBreakIteratorService ) ) ); + Reference< XBreakIterator > xBreakIter( xBI, UNO_QUERY ); + if ( !xBreakIter.is() ) + { + ShowServiceNotAvailableError( m_pUIParent, sBreakIteratorService, sal_True ); + } + else + { + sal_Int32 nNextAsianScript = xBreakIter->beginOfScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN ); + if ( -1 == nNextAsianScript ) + nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN ); + if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) ) + { // found asian text + + // determine if it's Hangul + CharClass aCharClassificaton( m_xORB, m_aSourceLocale ); + sal_Int16 nScript = aCharClassificaton.getScript( m_sCurrentPortion, sal::static_int_cast< USHORT >(nNextAsianScript) ); + if ( ( UnicodeScript_kHangulJamo == nScript ) + || ( UnicodeScript_kHangulCompatibilityJamo == nScript ) + || ( UnicodeScript_kHangulSyllable == nScript ) + ) + { + rDirection = HHC::eHangulToHanja; + } + else + { + rDirection = HHC::eHanjaToHangul; + } + + bSuccess = true; + } + } + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" ); + } + } + + return bSuccess; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::DoDocumentConversion( ) + { + // clear the change-all list - it's to be re-initialized for every single document + { + StringMap aEmpty; + m_aChangeList.swap( aEmpty ); + } + + // first of all, we need to guess the direction of our conversion - it is determined by the first + // hangul or hanja character in the first text + if ( !implRetrieveNextPortion() ) + { + DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" ); + // nothing to do + return; + } + if( m_eConvType == HHC::eConvHangulHanja ) + { + //init conversion direction from saved value + HHC::ConversionDirection eDirection = HHC::eHangulToHanja; + if(!implGetConversionDirectionForCurrentPortion( eDirection )) + // something went wrong, has already been asserted + return; + + if (m_pAntiImpl->IsUseSavedConversionDirectionState()) + { + m_ePrimaryConversionDirection = m_pAntiImpl->m_ePrimaryConversionDirectionSave; + m_bTryBothDirections = m_pAntiImpl->m_bTryBothDirectionsSave; + if( m_bTryBothDirections ) + m_eCurrentConversionDirection = eDirection; + else + m_eCurrentConversionDirection = m_ePrimaryConversionDirection; + } + else + { + m_ePrimaryConversionDirection = eDirection; + m_eCurrentConversionDirection = eDirection; + } + } + + if (m_bIsInteractive && m_eConvType == HHC::eConvHangulHanja) + { + //always open dialog if at least having a hangul or hanja text portion + createDialog(); + if(m_pAntiImpl->IsUseSavedConversionDirectionState()) + ContinueConversion( sal_False ); + else + implUpdateData(); + m_pConversionDialog->Execute(); + DELETEZ( m_pConversionDialog ); + } + else + { +#ifdef DBG_UTIL + sal_Bool bCompletelyDone = +#endif + ContinueConversion( sal_False ); + DBG_ASSERT( bCompletelyDone, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" ); + } + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit ) + { + if ( ContinueConversion( _bRepeatCurrentUnit ) ) + { // we're done with the whole document + DBG_ASSERT( !m_bIsInteractive || m_pConversionDialog, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" ); + if ( m_pConversionDialog ) + m_pConversionDialog->EndDialog( RET_OK ); + } + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implChange( const ::rtl::OUString& _rChangeInto ) + { + if( !_rChangeInto.getLength() ) + return; + + // translate the conversion format into a replacement action + // this translation depends on whether we have a Hangul original, or a Hanja original + + HHC::ReplacementAction eAction( HHC::eExchange ); + + if (m_eConvType == HHC::eConvHangulHanja) + { + // is the original we're about to change in Hangul? + sal_Bool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection; + + switch ( m_eConversionFormat ) + { + case HHC::eSimpleConversion: eAction = HHC::eExchange; break; + case HHC::eHangulBracketed: eAction = bOriginalIsHangul ? HHC::eOriginalBracketed : HHC::eReplacementBracketed; break; + case HHC::eHanjaBracketed: eAction = bOriginalIsHangul ? HHC::eReplacementBracketed : HHC::eOriginalBracketed; break; + case HHC::eRubyHanjaAbove: eAction = bOriginalIsHangul ? HHC::eReplacementAbove : HHC::eOriginalAbove; break; + case HHC::eRubyHanjaBelow: eAction = bOriginalIsHangul ? HHC::eReplacementBelow : HHC::eOriginalBelow; break; + case HHC::eRubyHangulAbove: eAction = bOriginalIsHangul ? HHC::eOriginalAbove : HHC::eReplacementAbove; break; + case HHC::eRubyHangulBelow: eAction = bOriginalIsHangul ? HHC::eOriginalBelow : HHC::eReplacementBelow; break; + default: + DBG_ERROR( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" ); + } + } + + // the proper indicies (the wrapper implementation needs indicies relative to the + // previous replacement) + DBG_ASSERT( ( m_nReplacementBaseIndex <= m_nCurrentStartIndex ) && ( m_nReplacementBaseIndex <= m_nCurrentEndIndex ), + "HangulHanjaConversion_Impl::implChange: invalid replacement base!" ); + + sal_Int32 nStartIndex = m_nCurrentStartIndex - m_nReplacementBaseIndex; + sal_Int32 nEndIndex = m_nCurrentEndIndex - m_nReplacementBaseIndex; + + //remind this decision + m_aRecentlyUsedList[ GetCurrentUnit() ] = _rChangeInto; + + LanguageType *pNewUnitLang = 0; + LanguageType nNewUnitLang = LANGUAGE_NONE; + if (m_eConvType == HHC::eConvSimplifiedTraditional) + { + // check if language needs to be changed + if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL && + !m_pAntiImpl->IsTraditional( m_nCurrentPortionLang )) + nNewUnitLang = LANGUAGE_CHINESE_TRADITIONAL; + else if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED && + !m_pAntiImpl->IsSimplified( m_nCurrentPortionLang )) + nNewUnitLang = LANGUAGE_CHINESE_SIMPLIFIED; + if (nNewUnitLang != LANGUAGE_NONE) + pNewUnitLang = &nNewUnitLang; + } + + // according to FT we should not (yet) bother about Hangul/Hanja conversion here + // + // aOffsets is needed in ReplaceUnit below in order to to find out + // exactly which characters are really changed in order to keep as much + // from attributation for the text as possible. + Sequence< sal_Int32 > aOffsets; + Reference< XExtendedTextConversion > xExtConverter( m_xConverter, UNO_QUERY ); + if (m_eConvType == HHC::eConvSimplifiedTraditional && xExtConverter.is()) + { + try + { + ::rtl::OUString aConvText = xExtConverter->getConversionWithOffset( + m_sCurrentPortion, + m_nCurrentStartIndex, + m_nCurrentEndIndex - m_nCurrentStartIndex, + m_aSourceLocale, + m_nCurrentConversionType, + m_nCurrentConversionOption, + aOffsets + ); + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" ); + aOffsets.realloc(0); + } + } + + // do the replacement + m_pAntiImpl->ReplaceUnit( nStartIndex, nEndIndex, m_sCurrentPortion, + _rChangeInto, aOffsets, eAction, pNewUnitLang ); + + + // adjust the replacement base + m_nReplacementBaseIndex = m_nCurrentEndIndex; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration() + { + SvtLinguConfig aLngCfg; + aLngCfg.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD ) >>= m_bIgnorePostPositionalWord; + aLngCfg.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST ) >>= m_bShowRecentlyUsedFirst; + aLngCfg.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES ) >>= m_bAutoReplaceUnique; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implUpdateData() + { + implReadOptionsFromConfiguration(); + implUpdateSuggestions(); + + if(m_pConversionDialog) + { + ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); + + m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions ); + m_pConversionDialog->FocusSuggestion(); + } + + m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex ); + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnOptionsChanged, void*, EMPTYARG ) + { + //options and dictionaries might have been changed + //-> update our internal settings and the dialog + implUpdateData(); + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnIgnore, void*, EMPTYARG ) + { + // simply ignore, and proceed + implProceed( sal_False ); + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnIgnoreAll, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" ); + + if ( m_pConversionDialog ) + { + String sCurrentUnit = m_pConversionDialog->GetCurrentString(); + DBG_ASSERT( m_sIgnoreList.end() == m_sIgnoreList.find( sCurrentUnit ), + "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" ); + + // put into the "ignore all" list + m_sIgnoreList.insert( sCurrentUnit ); + + // and proceed + implProceed( sal_False ); + } + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnChange, void*, EMPTYARG ) + { + // change + DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); + if( m_pConversionDialog ) + implChange( m_pConversionDialog->GetCurrentSuggestion( ) ); + // and proceed + implProceed( sal_False ); + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnChangeAll, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" ); + if ( m_pConversionDialog ) + { + ::rtl::OUString sCurrentUnit( m_pConversionDialog->GetCurrentString() ); + ::rtl::OUString sChangeInto( m_pConversionDialog->GetCurrentSuggestion( ) ); + + if( sChangeInto.getLength() ) + { + // change the current occurence + implChange( sChangeInto ); + + // put into the "change all" list + m_aChangeList.insert( StringMap::value_type( sCurrentUnit, sChangeInto ) ); + } + + // and proceed + implProceed( sal_False ); + } + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnByCharClicked, CheckBox*, _pBox ) + { + m_bByCharacter = _pBox->IsChecked(); + + // continue conversion, without advancing to the next unit, but instead continuing with the current unit + implProceed( sal_True ); + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnConversionTypeChanged, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); + if( m_pConversionDialog ) + m_eConversionFormat = m_pConversionDialog->GetConversionFormat( ); + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnFind, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnFind: where did this come from?" ); + if ( m_pConversionDialog ) + { + try + { + ::rtl::OUString sNewOriginal( m_pConversionDialog->GetCurrentSuggestion( ) ); + Sequence< ::rtl::OUString > aSuggestions; + + DBG_ASSERT( m_xConverter.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" ); + TextConversionResult aToHanja = m_xConverter->getConversions( + sNewOriginal, + 0, sNewOriginal.getLength(), + m_aSourceLocale, + TextConversionType::TO_HANJA, + TextConversionOption::NONE + ); + TextConversionResult aToHangul = m_xConverter->getConversions( + sNewOriginal, + 0, sNewOriginal.getLength(), + m_aSourceLocale, + TextConversionType::TO_HANGUL, + TextConversionOption::NONE + ); + + bool bHaveToHanja = ( aToHanja.Boundary.startPos < aToHanja.Boundary.endPos ); + bool bHaveToHangul = ( aToHangul.Boundary.startPos < aToHangul.Boundary.endPos ); + + TextConversionResult* pResult = NULL; + if ( bHaveToHanja && bHaveToHangul ) + { // it found convertibles in both directions -> use the first + if ( aToHangul.Boundary.startPos < aToHanja.Boundary.startPos ) + pResult = &aToHangul; + else + pResult = &aToHanja; + } + else if ( bHaveToHanja ) + { // only found toHanja + pResult = &aToHanja; + } + else + { // only found toHangul + pResult = &aToHangul; + } + if ( pResult ) + aSuggestions = pResult->Candidates; + + m_pConversionDialog->SetCurrentString( sNewOriginal, aSuggestions, false ); + m_pConversionDialog->FocusSuggestion(); + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::OnFind: caught an exception!" ); + } + } + return 0L; + } + + //========================================================================= + //= HangulHanjaConversion + //========================================================================= + //------------------------------------------------------------------------- + + // static member initialization + sal_Bool HangulHanjaConversion::m_bUseSavedValues = sal_False; + sal_Bool HangulHanjaConversion::m_bTryBothDirectionsSave = sal_False; + HHC::ConversionDirection HangulHanjaConversion::m_ePrimaryConversionDirectionSave = HHC::eHangulToHanja; + + //------------------------------------------------------------------------- + HangulHanjaConversion::HangulHanjaConversion( Window* _pUIParent, + const Reference< XMultiServiceFactory >& _rxORB, + const Locale& _rSourceLocale, const Locale& _rTargetLocale, + const Font* _pTargetFont, + sal_Int32 _nOptions, sal_Bool _bIsInteractive) + :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent, _rxORB, _rSourceLocale, _rTargetLocale, _pTargetFont, _nOptions, _bIsInteractive, this ) ) + { + } + + //------------------------------------------------------------------------- + HangulHanjaConversion::~HangulHanjaConversion( ) + { + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::SetUseSavedConversionDirectionState( sal_Bool bVal ) + { + m_bUseSavedValues = bVal; + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion::IsUseSavedConversionDirectionState() + { + return m_bUseSavedValues; + } + + //------------------------------------------------------------------------- + LanguageType HangulHanjaConversion::GetSourceLanguage( ) const + { + return m_pImpl->GetSourceLang(); + } + + //------------------------------------------------------------------------- + LanguageType HangulHanjaConversion::GetTargetLanguage( ) const + { + return m_pImpl->GetTargetLang(); + } + + //------------------------------------------------------------------------- + const Font * HangulHanjaConversion::GetTargetFont( ) const + { + return m_pImpl->GetTargetFont(); + } + + //------------------------------------------------------------------------- + sal_Int32 HangulHanjaConversion::GetConversionOptions( ) const + { + return m_pImpl->GetConvOptions(); + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion::IsInteractive( ) const + { + return m_pImpl->IsInteractive(); + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::HandleNewUnit( const sal_Int32, const sal_Int32 ) + { + // nothing to do, only derived classes need this. + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::GetNextPortion( ::rtl::OUString&, LanguageType&, sal_Bool ) + { + DBG_ERROR( "HangulHanjaConversion::GetNextPortion: to be overridden!" ); + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::ReplaceUnit( + const sal_Int32, const sal_Int32, + const ::rtl::OUString&, + const ::rtl::OUString&, + const ::com::sun::star::uno::Sequence< sal_Int32 > &, + ReplacementAction, + LanguageType * ) + { + DBG_ERROR( "HangulHanjaConversion::ReplaceUnit: to be overridden!" ); + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion::HasRubySupport() const + { + DBG_ERROR( "HangulHanjaConversion::HasRubySupport: to be overridden!" ); + return sal_False; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::ConvertDocument() + { + if ( m_pImpl->IsValid() ) + m_pImpl->DoDocumentConversion( ); + } + +//............................................................................. +} // namespace svx +//............................................................................. + diff --git a/editeng/source/misc/lingu.src b/editeng/source/misc/lingu.src new file mode 100644 index 000000000000..0d86b757f850 --- /dev/null +++ b/editeng/source/misc/lingu.src @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + // include --------------------------------------------------------------- +#include <editeng/editrids.hrc> + // pragma ---------------------------------------------------------------- + + // QueryBoxen --------------------------------------------------------------- +QueryBox RID_SVXQB_CONTINUE +{ + BUTTONS = WB_YES_NO ; + DEFBUTTON = WB_DEF_YES ; + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Anfang des Dokumentes fortsetzen? : šberpr³fung am Anfang des Dokumentes fortsetzen? */ + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Anfang des Dokumentes fortsetzen? : šberpr³fung am Anfang des Dokumentes fortsetzen? */ + Message [ en-US ] = "Continue checking at beginning of document?" ; +}; +QueryBox RID_SVXQB_BW_CONTINUE +{ + BUTTONS = WB_YES_NO ; + DEFBUTTON = WB_DEF_YES ; + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Ende des Dokumentes fortsetzen? : šberpr³fung am Ende des Dokumentes fortsetzen? */ + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Ende des Dokumentes fortsetzen? : šberpr³fung am Ende des Dokumentes fortsetzen? */ + Message [ en-US ] = "Continue checking at end of document?" ; +}; +String RID_SVXSTR_HMERR_THESAURUS +{ + /* ### ACHTUNG: Neuer Text in Resource? Ein Thesaurus für die eingestellte Sprache ist nicht verfügbar. \nÜberprüfen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gewünschte Sprache : Ein Thesaurus f³r die eingestellte Sprache ist nicht verf³gbar. \nšberpr³fen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gew³nschte Sprache */ + /* ### ACHTUNG: Neuer Text in Resource? Ein Thesaurus für die eingestellte Sprache ist nicht verfügbar. \nÜberprüfen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gewünschte Sprache : Ein Thesaurus f³r die eingestellte Sprache ist nicht verf³gbar. \nšberpr³fen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gew³nschte Sprache */ + Text [ en-US ] = "No thesaurus is available for the selected language. \nPlease check your installation and install the desired language\n" ; +}; +String RID_SVXSTR_DIC_ERR_UNKNOWN +{ + Text [ en-US ] = "Word cannot be added to dictionary\ndue to unknown reason."; +}; +String RID_SVXSTR_DIC_ERR_FULL +{ + Text [ en-US ] = "The dictionary is already full."; +}; +String RID_SVXSTR_DIC_ERR_READONLY +{ + Text [ en-US ] = "The dictionary is read-only."; +}; + + // ********************************************************************** EOF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/editeng/source/misc/makefile.mk b/editeng/source/misc/makefile.mk new file mode 100644 index 000000000000..7eb2d80447a1 --- /dev/null +++ b/editeng/source/misc/makefile.mk @@ -0,0 +1,71 @@ +#************************************************************************* +# +# 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: makefile.mk,v $ +# +# $Revision: 1.18 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +PRJNAME=editeng +TARGET=misc + +#PROJECTPCH4DLL=TRUE +#PROJECTPCH=eeng_pch +#PROJECTPCHSOURCE=eeng_pch + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Allgemein ---------------------------------------------------------- + +.IF "$(editdebug)" != "" || "$(EDITDEBUG)" != "" +CDEFS+=-DEDITDEBUG +.ENDIF + +SLOFILES = \ + $(SLO)$/edtdlg.obj \ + $(SLO)$/unolingu.obj \ + $(SLO)$/acorrcfg.obj \ + $(SLO)$/forbiddencharacterstable.obj \ + $(SLO)$/hangulhanja.obj \ + $(SLO)$/splwrap.obj \ + $(SLO)$/svxacorr.obj \ + $(SLO)$/SvXMLAutoCorrectExport.obj \ + $(SLO)$/SvXMLAutoCorrectImport.obj \ + $(SLO)$/swafopt.obj \ + $(SLO)$/txtrange.obj + +SRS1NAME=misc +SRC1FILES = \ + lingu.src + +.INCLUDE : target.mk + diff --git a/editeng/source/misc/splwrap.cxx b/editeng/source/misc/splwrap.cxx new file mode 100644 index 000000000000..3df64c26a594 --- /dev/null +++ b/editeng/source/misc/splwrap.cxx @@ -0,0 +1,632 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include<rtl/ustring.hxx> +#include <tools/shl.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/svapp.hxx> +#include <vcl/msgbox.hxx> +#include <tools/debug.hxx> +#include <svtools/langtab.hxx> + +#ifndef __RSC +#include <tools/errinf.hxx> +#endif +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <com/sun/star/frame/XStorable.hpp> + +#include <map> + +#include <editeng/svxenum.hxx> +#include <editeng/splwrap.hxx> // Der Wrapper +#include <editeng/edtdlg.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> +#include <editeng/editids.hrc> +#include <editeng/editerr.hxx> + +#define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); } + +#define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); } + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::linguistic2; + + +// misc functions --------------------------------------------- + +void SvxPrepareAutoCorrect( String &rOldText, String &rNewText ) +{ + // This function should be used to strip (or add) trailing '.' from + // the strings before passing them on to the autocorrect function in + // order that the autocorrect function will hopefully + // works properly with normal words and abbreviations (with trailing '.') + // independ of if they are at the end of the sentence or not. + // + // rOldText: text to be replaced + // rNewText: replacement text + + xub_StrLen nOldLen = rOldText.Len(), + nNewLen = rNewText.Len(); + if (nOldLen && nNewLen) + { + sal_Bool bOldHasDot = sal_Unicode( '.' ) == rOldText.GetChar( nOldLen - 1 ), + bNewHasDot = sal_Unicode( '.' ) == rNewText.GetChar( nNewLen - 1 ); + if (bOldHasDot && !bNewHasDot + /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/) + rOldText.Erase( nOldLen - 1 ); + } +} + +// ----------------------------------------------------------------------- + +#define SVX_LANG_NEED_CHECK 0 +#define SVX_LANG_OK 1 +#define SVX_LANG_MISSING 2 +#define SVX_LANG_MISSING_DO_WARN 3 + +#define SVX_FLAGS_NEW + + +struct lt_LanguageType +{ + bool operator()( LanguageType n1, LanguageType n2 ) const + { + return n1 < n2; + } +}; + +typedef std::map< LanguageType, USHORT, lt_LanguageType > LangCheckState_map_t; + +static LangCheckState_map_t & GetLangCheckState() +{ + static LangCheckState_map_t aLangCheckState; + return aLangCheckState; +} + +void SvxSpellWrapper::ShowLanguageErrors() +{ + // display message boxes for languages not available for + // spellchecking or hyphenation + LangCheckState_map_t &rLCS = GetLangCheckState(); + LangCheckState_map_t::iterator aIt( rLCS.begin() ); + while (aIt != rLCS.end()) + { + LanguageType nLang = aIt->first; + sal_uInt16 nVal = aIt->second; + sal_uInt16 nTmpSpell = nVal & 0x00FF; + sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF; + + if (SVX_LANG_MISSING_DO_WARN == nTmpSpell) + { + String aErr( SvtLanguageTable::GetLanguageString( nLang ) ); + ErrorHandler::HandleError( + *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); + nTmpSpell = SVX_LANG_MISSING; + } + if (SVX_LANG_MISSING_DO_WARN == nTmpHyph) + { + String aErr( SvtLanguageTable::GetLanguageString( nLang ) ); + ErrorHandler::HandleError( + *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); + nTmpHyph = SVX_LANG_MISSING; + } + + rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell; + ++aIt; + } + +} + +SvxSpellWrapper::~SvxSpellWrapper() +{ +} + +/*-------------------------------------------------------------------- + * Beschreibung: Ctor, die Pruefreihenfolge wird festgelegt + * + * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER + * !bStart && bOtherCntnt: OTHER, BODY + * bStart && !bOtherCntnt: BODY_END, OTHER + * bStart && bOtherCntnt: OTHER + * + --------------------------------------------------------------------*/ + +SvxSpellWrapper::SvxSpellWrapper( Window* pWn, + Reference< XSpellChecker1 > &xSpellChecker, + const sal_Bool bStart, const sal_Bool bIsAllRight, + const sal_Bool bOther, const sal_Bool bRevAllow ) : + + pWin ( pWn ), + xSpell ( xSpellChecker ), + bOtherCntnt ( bOther ), + bDialog ( sal_False ), + bHyphen ( sal_False ), + bAuto ( sal_False ), + bStartChk ( bOther ), + bRevAllowed ( bRevAllow ), + bAllRight ( bIsAllRight ) +{ + Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() ); + sal_Bool bWrapReverse = xProp.is() ? + *(sal_Bool*)xProp->getPropertyValue( + ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue() + : sal_False; + bReverse = bRevAllow && bWrapReverse; + bStartDone = bOther || ( !bReverse && bStart ); + bEndDone = bReverse && bStart && !bOther; +} + +// ----------------------------------------------------------------------- + +SvxSpellWrapper::SvxSpellWrapper( Window* pWn, + Reference< XHyphenator > &xHyphenator, + const sal_Bool bStart, const sal_Bool bOther ) : + pWin ( pWn ), + xHyph ( xHyphenator ), + bOtherCntnt ( bOther ), + bDialog ( sal_False ), + bHyphen ( sal_False ), + bAuto ( sal_False ), + bReverse ( sal_False ), + bStartDone ( bOther || ( !bReverse && bStart ) ), + bEndDone ( bReverse && bStart && !bOther ), + bStartChk ( bOther ), + bRevAllowed ( sal_False ), + bAllRight ( sal_True ) +{ +} + +// ----------------------------------------------------------------------- + +sal_Int16 SvxSpellWrapper::CheckSpellLang( + Reference< XSpellChecker1 > xSpell, sal_Int16 nLang) +{ + LangCheckState_map_t &rLCS = GetLangCheckState(); + + LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) ); + sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second; + + if (aIt == rLCS.end()) + rLCS[ nLang ] = nVal; + + if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF)) + { + sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN; + if (xSpell.is() && xSpell->hasLanguage( nLang )) + nTmpVal = SVX_LANG_OK; + nVal &= 0xFF00; + nVal |= nTmpVal; + + rLCS[ nLang ] = nVal; + } + + return (sal_Int16) nVal; +} + +sal_Int16 SvxSpellWrapper::CheckHyphLang( + Reference< XHyphenator > xHyph, sal_Int16 nLang) +{ + LangCheckState_map_t &rLCS = GetLangCheckState(); + + LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) ); + sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second; + + if (aIt == rLCS.end()) + rLCS[ nLang ] = nVal; + + if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF)) + { + sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN; + if (xHyph.is() && xHyph->hasLocale( SvxCreateLocale( nLang ) )) + nTmpVal = SVX_LANG_OK; + nVal &= 0x00FF; + nVal |= nTmpVal << 8; + + rLCS[ nLang ] = nVal; + } + + return (sal_Int16) nVal; +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ ) +{ // Hier muessen die notwendigen Vorbereitungen fuer SpellContinue +} // im uebergebenen Bereich getroffen werden. + +// ----------------------------------------------------------------------- + + +sal_Bool SvxSpellWrapper::HasOtherCnt() +{ + return sal_False; // Gibt es ueberhaupt einen Sonderbereich? +} + +// ----------------------------------------------------------------------- + + +sal_Bool SvxSpellWrapper::SpellMore() +{ + return sal_False; // Sollen weitere Dokumente geprueft werden? +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::SpellEnd() +{ // Bereich ist abgeschlossen, ggf. Aufraeumen + + // display error for last language not found + ShowLanguageErrors(); +} + +// ----------------------------------------------------------------------- + + +sal_Bool SvxSpellWrapper::SpellContinue() +{ + return sal_False; +} + +// ----------------------------------------------------------------------- + +void SvxSpellWrapper::AutoCorrect( const String&, const String& ) +{ +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::ScrollArea() +{ // Scrollarea einstellen +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 ) +{ // Wort ersetzen +} + +// ----------------------------------------------------------------------- + + +String SvxSpellWrapper::GetThesWord() +{ + // Welches Wort soll nachgeschlagen werden? + return String(); +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::ChangeThesWord( const String& ) +{ + // Wort wg. Thesaurus ersetzen +} + +// ----------------------------------------------------------------------- + +void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage ) +{ + Reference< XThesaurus > xThes( SvxGetThesaurus() ); + if (!xThes.is()) + { + InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute(); + return; + } + + WAIT_ON(); // while looking up for initial word + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage ); + WAIT_OFF(); + if ( pDlg->Execute()== RET_OK ) + { + ChangeThesWord( pDlg->GetWord() ); + } + delete pDlg; +} + +// ----------------------------------------------------------------------- + +void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 ) +{ // Wort aus der Replace-Liste ersetzen +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::SetLanguage( const sal_uInt16 ) +{ // Sprache aendern +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::InsertHyphen( const sal_uInt16 ) +{ // Hyphen einfuegen bzw. loeschen +} + +// ----------------------------------------------------------------------- +// Pruefung der Dokumentbereiche in der durch die Flags angegebenen Reihenfolge + + +void SvxSpellWrapper::SpellDocument( ) +{ + if ( bOtherCntnt ) + { + bReverse = sal_False; + SpellStart( SVX_SPELL_OTHER ); + } + else + { + bStartChk = bReverse; + SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); + } + + if ( FindSpellError() ) + { + Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY ); + Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY ); + + Window *pOld = pWin; + bDialog = sal_True; + if (xHyphWord.is()) + { + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin, + xHyphWord->getWord(), + SvxLocaleToLanguage( xHyphWord->getLocale() ), + xHyph, this ); + pWin = pDlg->GetWindow(); + pDlg->Execute(); + delete pDlg; + } + bDialog = sal_False; + pWin = pOld; + }; +} + +// ----------------------------------------------------------------------- +// Naechsten Bereich auswaehlen + + +sal_Bool SvxSpellWrapper::SpellNext( ) +{ + Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() ); + sal_Bool bWrapReverse = xProp.is() ? + *(sal_Bool*)xProp->getPropertyValue( + ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue() + : sal_False; + sal_Bool bActRev = bRevAllowed && bWrapReverse; + + // bActRev ist die Richtung nach dem Spellen, bReverse die am Anfang. + if( bActRev == bReverse ) + { // Keine Richtungsaenderung, also ist + if( bStartChk ) // der gewuenschte Bereich ( bStartChk ) + bStartDone = sal_True; // vollstaendig abgearbeitet. + else + bEndDone = sal_True; + } + else if( bReverse == bStartChk ) // Bei einer Richtungsaenderung kann + { // u.U. auch ein Bereich abgearbeitet sein. + if( bStartChk ) // Sollte der vordere Teil rueckwaerts gespellt + bEndDone = sal_True; // werden und wir kehren unterwegs um, so ist + else // der hintere Teil abgearbeitet (und umgekehrt). + bStartDone = sal_True; + } + + bReverse = bActRev; + if( bOtherCntnt && bStartDone && bEndDone ) // Dokument komplett geprueft? + { + if ( SpellMore() ) // ein weiteres Dokument pruefen? + { + bOtherCntnt = sal_False; + bStartDone = !bReverse; + bEndDone = bReverse; + SpellStart( SVX_SPELL_BODY ); + return sal_True; + } + return sal_False; + } + + sal_Bool bGoOn = sal_False; + + if ( bOtherCntnt ) + { + bStartChk = sal_False; + SpellStart( SVX_SPELL_BODY ); + bGoOn = sal_True; + } + else if ( bStartDone && bEndDone ) + { + sal_Bool bIsSpellSpecial = xProp.is() ? + *(sal_Bool*)xProp->getPropertyValue( + ::rtl::OUString::createFromAscii(UPN_IS_SPELL_SPECIAL) ).getValue() + : sal_False; + // Bodybereich erledigt, Frage nach Sonderbereich + if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() ) + { + SpellStart( SVX_SPELL_OTHER ); + bOtherCntnt = bGoOn = sal_True; + } + else if ( SpellMore() ) // ein weiteres Dokument pruefen? + { + bOtherCntnt = sal_False; + bStartDone = !bReverse; + bEndDone = bReverse; + SpellStart( SVX_SPELL_BODY ); + return sal_True; + } + } + else + { + // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich + WAIT_OFF(); + +// Sobald im Dialog das DontWrapAround gesetzt werden kann, kann der +// folgende #ifdef-Zweig aktiviert werden ... +#ifdef USED + sal_Bool bDontWrapAround = IsHyphen() ? + pSpell->GetOptions() & DONT_WRAPAROUND : + pSpell->GetHyphOptions() & HYPH_DONT_WRAPAROUND; + if( bDontWrapAround ) +#else + sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE; + QueryBox aBox( pWin, EditResId( nResId ) ); + if ( aBox.Execute() != RET_YES ) +#endif + + { + // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich + WAIT_ON(); + bStartDone = bEndDone = sal_True; + return SpellNext(); + } + else + { + bStartChk = !bStartDone; + SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); + bGoOn = sal_True; + } + WAIT_ON(); + } + return bGoOn; +} + +// ----------------------------------------------------------------------- + +Reference< XDictionary > SvxSpellWrapper::GetAllRightDic() const +{ + Reference< XDictionary > xDic; + + Reference< XDictionaryList > xDicList( SvxGetDictionaryList() ); + if (xDicList.is()) + { + Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() ); + const Reference< XDictionary > *pDic = aDics.getConstArray(); + sal_Int32 nCount = aDics.getLength(); + + sal_Int32 i = 0; + while (!xDic.is() && i < nCount) + { + Reference< XDictionary > xTmp( pDic[i], UNO_QUERY ); + if (xTmp.is()) + { + if ( xTmp->isActive() && + xTmp->getDictionaryType() != DictionaryType_NEGATIVE && + SvxLocaleToLanguage( xTmp->getLocale() ) == LANGUAGE_NONE ) + { + Reference< frame::XStorable > xStor( xTmp, UNO_QUERY ); + if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly()) + { + xDic = xTmp; + } + } + } + ++i; + } + + if (!xDic.is()) + { + xDic = SvxGetOrCreatePosDic( xDicList ); + if (xDic.is()) + xDic->setActive( sal_True ); + } + } + + return xDic; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxSpellWrapper::FindSpellError() +{ + ShowLanguageErrors(); + + Reference< XInterface > xRef; + + WAIT_ON(); + sal_Bool bSpell = sal_True; + + Reference< XDictionary > xAllRightDic; + if (IsAllRight()) + xAllRightDic = GetAllRightDic(); + + while ( bSpell ) + { + SpellContinue(); + + Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY ); + Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY ); + + if (xAlt.is()) + { + if (IsAllRight() && xAllRightDic.is()) + { + xAllRightDic->add( xAlt->getWord(), sal_False, ::rtl::OUString() ); + } + else + { + // look up in ChangeAllList for misspelled word + Reference< XDictionary > xChangeAllList( + SvxGetChangeAllList(), UNO_QUERY ); + Reference< XDictionaryEntry > xEntry; + if (xChangeAllList.is()) + xEntry = xChangeAllList->getEntry( xAlt->getWord() ); + + if (xEntry.is()) + { + // replace word without asking + ReplaceAll( xEntry->getReplacementText(), + SvxLocaleToLanguage( xAlt->getLocale() ) ); + } + else + bSpell = sal_False; + } + } + else if (xHyphWord.is()) + bSpell = sal_False; + else + { + SpellEnd(); + bSpell = SpellNext(); + } + } + WAIT_OFF(); + return GetLast().is(); +} + + + diff --git a/editeng/source/misc/svxacorr.cxx b/editeng/source/misc/svxacorr.cxx new file mode 100644 index 000000000000..64343517c69f --- /dev/null +++ b/editeng/source/misc/svxacorr.cxx @@ -0,0 +1,2788 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + + +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <tools/urlobj.hxx> +#include <tools/table.hxx> +#include <i18npool/mslangid.hxx> +#include <vcl/svapp.hxx> +#include <sot/storinfo.hxx> +// fuer die Sort-String-Arrays aus dem SVMEM.HXX +#define _SVSTDARR_STRINGSISORTDTOR +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <svl/fstathelper.hxx> +#include <svtools/helpopt.hxx> +#include <svl/urihelper.hxx> +#include <unotools/charclass.hxx> +#include <com/sun/star/i18n/UnicodeType.hdl> +#include <unotools/collatorwrapper.hxx> +#include <com/sun/star/i18n/CollatorOptions.hpp> +#include <unotools/localedatawrapper.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <editeng/editids.hrc> +#include <sot/storage.hxx> +#include <comphelper/storagehelper.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/svxacorr.hxx> +#include <editeng/unolingu.hxx> +#include <helpid.hrc> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/xml/sax/InputSource.hpp> +#include <com/sun/star/xml/sax/XParser.hpp> +#include <unotools/streamwrap.hxx> +#include <SvXMLAutoCorrectImport.hxx> +#include <SvXMLAutoCorrectExport.hxx> +#include <ucbhelper/content.hxx> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <xmloff/xmltoken.hxx> +#include <vcl/help.hxx> + +#define CHAR_HARDBLANK ((sal_Unicode)0x00A0) + +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::rtl; +using namespace ::utl; + +const int C_NONE = 0x00; +const int C_FULL_STOP = 0x01; +const int C_EXCLAMATION_MARK = 0x02; +const int C_QUESTION_MARK = 0x04; + +static const sal_Char pImplWrdStt_ExcptLstStr[] = "WordExceptList"; +static const sal_Char pImplCplStt_ExcptLstStr[] = "SentenceExceptList"; +static const sal_Char pImplAutocorr_ListStr[] = "DocumentList"; +static const sal_Char pXMLImplWrdStt_ExcptLstStr[] = "WordExceptList.xml"; +static const sal_Char pXMLImplCplStt_ExcptLstStr[] = "SentenceExceptList.xml"; +static const sal_Char pXMLImplAutocorr_ListStr[] = "DocumentList.xml"; + +static const sal_Char + /* auch bei diesen Anfaengen - Klammern auf und alle Arten von Anf.Zei. */ + sImplSttSkipChars[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94", + /* auch bei diesen Ende - Klammern auf und alle Arten von Anf.Zei. */ + sImplEndSkipChars[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94"; + +// diese Zeichen sind in Worten erlaubt: (fuer FnCptlSttSntnc) +static const sal_Char sImplWordChars[] = "-'"; + +void EncryptBlockName_Imp( String& rName ); +void DecryptBlockName_Imp( String& rName ); + + +// FileVersions Nummern fuer die Ersetzungs-/Ausnahmelisten getrennt +#define WORDLIST_VERSION_358 1 +#define EXEPTLIST_VERSION_358 0 + + +_SV_IMPL_SORTAR_ALG( SvxAutocorrWordList, SvxAutocorrWordPtr ) +TYPEINIT0(SvxAutoCorrect) + +typedef SvxAutoCorrectLanguageLists* SvxAutoCorrectLanguageListsPtr; +DECLARE_TABLE( SvxAutoCorrLanguageTable_Impl, SvxAutoCorrectLanguageListsPtr) + +DECLARE_TABLE( SvxAutoCorrLastFileAskTable_Impl, long ) + + +inline int IsWordDelim( const sal_Unicode c ) +{ + return ' ' == c || '\t' == c || 0x0a == c || + 0xA0 == c || 0x2011 == c || 0x1 == c; +} + +inline int IsLowerLetter( sal_Int32 nCharType ) +{ + return CharClass::isLetterType( nCharType ) && + 0 == ( ::com::sun::star::i18n::KCharacterType::UPPER & nCharType); +} +inline int IsUpperLetter( sal_Int32 nCharType ) +{ + return CharClass::isLetterType( nCharType ) && + 0 == ( ::com::sun::star::i18n::KCharacterType::LOWER & nCharType); +} + +BOOL lcl_IsSymbolChar( CharClass& rCC, const String& rTxt, + xub_StrLen nStt, xub_StrLen nEnd ) +{ + for( ; nStt < nEnd; ++nStt ) + { +#if OSL_DEBUG_LEVEL > 1 + sal_Int32 nCharType; + sal_Int32 nChType; + nCharType = rCC.getCharacterType( rTxt, nStt ); + nChType = rCC.getType( rTxt, nStt ); +#endif + if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE == + rCC.getType( rTxt, nStt )) + return TRUE; + } + return FALSE; +} + + +static BOOL lcl_IsInAsciiArr( const sal_Char* pArr, const sal_Unicode c ) +{ + BOOL bRet = FALSE; + for( ; *pArr; ++pArr ) + if( *pArr == c ) + { + bRet = TRUE; + break; + } + return bRet; +} + +SvxAutoCorrDoc::~SvxAutoCorrDoc() +{ +} + + + // wird nach dem austauschen der Zeichen von den Funktionen + // - FnCptlSttWrd + // - FnCptlSttSntnc + // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten + // aufgenommen werden. +void SvxAutoCorrDoc::SaveCpltSttWord( ULONG, xub_StrLen, const String&, + sal_Unicode ) +{ +} + +LanguageType SvxAutoCorrDoc::GetLanguage( xub_StrLen , BOOL ) const +{ + return LANGUAGE_SYSTEM; +} + +static ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& GetProcessFact() +{ + static ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory > xMSF = + ::comphelper::getProcessServiceFactory(); + return xMSF; +} + +static USHORT GetAppLang() +{ + return Application::GetSettings().GetLanguage(); +} +static LocaleDataWrapper& GetLocaleDataWrapper( USHORT nLang ) +{ + static LocaleDataWrapper aLclDtWrp( GetProcessFact(), + SvxCreateLocale( GetAppLang() ) ); + ::com::sun::star::lang::Locale aLcl( SvxCreateLocale( nLang )); + const ::com::sun::star::lang::Locale& rLcl = aLclDtWrp.getLoadedLocale(); + if( aLcl.Language != rLcl.Language || + aLcl.Country != rLcl.Country || + aLcl.Variant != rLcl.Variant ) + aLclDtWrp.setLocale( aLcl ); + return aLclDtWrp; +} +static TransliterationWrapper& GetIgnoreTranslWrapper() +{ + static int bIsInit = 0; + static TransliterationWrapper aWrp( GetProcessFact(), + ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE | + ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA | + ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH ); + if( !bIsInit ) + { + aWrp.loadModuleIfNeeded( GetAppLang() ); + bIsInit = 1; + } + return aWrp; +} +static CollatorWrapper& GetCollatorWrapper() +{ + static int bIsInit = 0; + static CollatorWrapper aCollWrp( GetProcessFact() ); + if( !bIsInit ) + { + aCollWrp.loadDefaultCollator( SvxCreateLocale( GetAppLang() ), 0 ); + bIsInit = 1; + } + return aCollWrp; +} + + +void SvxAutocorrWordList::DeleteAndDestroy( USHORT nP, USHORT nL ) +{ + if( nL ) + { + DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" ); + for( USHORT n=nP; n < nP + nL; n++ ) + delete *((SvxAutocorrWordPtr*)pData+n); + SvPtrarr::Remove( nP, nL ); + } +} + + +BOOL SvxAutocorrWordList::Seek_Entry( const SvxAutocorrWordPtr aE, USHORT* pP ) const +{ + register USHORT nO = SvxAutocorrWordList_SAR::Count(), + nM, + nU = 0; + if( nO > 0 ) + { + CollatorWrapper& rCmp = ::GetCollatorWrapper(); + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + long nCmp = rCmp.compareString( aE->GetShort(), + (*((SvxAutocorrWordPtr*)pData + nM))->GetShort() ); + if( 0 == nCmp ) + { + if( pP ) *pP = nM; + return TRUE; + } + else if( 0 < nCmp ) + nU = nM + 1; + else if( nM == 0 ) + { + if( pP ) *pP = nU; + return FALSE; + } + else + nO = nM - 1; + } + } + if( pP ) *pP = nU; + return FALSE; +} + +/* -----------------18.11.98 15:28------------------- + * + * --------------------------------------------------*/ +void lcl_ClearTable(SvxAutoCorrLanguageTable_Impl& rLangTable) +{ + SvxAutoCorrectLanguageListsPtr pLists = rLangTable.Last(); + while(pLists) + { + delete pLists; + pLists = rLangTable.Prev(); + } + rLangTable.Clear(); +} + +/* -----------------03.11.06 10:15------------------- + * + * --------------------------------------------------*/ + +sal_Bool SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar ) +{ + return cChar == '\0' || cChar == '\t' || cChar == 0x0a || + cChar == ' ' || cChar == '\'' || cChar == '\"' || + cChar == '*' || cChar == '_' || + cChar == '.' || cChar == ',' || cChar == ';' || + cChar == ':' || cChar == '?' || cChar == '!' || cChar == '/'; +} + +sal_Bool SvxAutoCorrect::NeedsHardspaceAutocorr( sal_Unicode cChar ) +{ + return cChar == ';' || cChar == ':' || cChar == '?' || cChar == '!' || + cChar == '/' /*case for the urls exception*/; +} + +/* -----------------19.11.98 10:15------------------- + * + * --------------------------------------------------*/ +long SvxAutoCorrect::GetDefaultFlags() +{ + long nRet = Autocorrect + | CptlSttSntnc + | CptlSttWrd + | ChgOrdinalNumber + | ChgToEnEmDash + | AddNonBrkSpace + | ChgWeightUnderl + | SetINetAttr + | ChgQuotes + | SaveWordCplSttLst + | SaveWordWrdSttLst; + LanguageType eLang = GetAppLang(); + switch( eLang ) + { + case LANGUAGE_ENGLISH: + case LANGUAGE_ENGLISH_US: + case LANGUAGE_ENGLISH_UK: + case LANGUAGE_ENGLISH_AUS: + case LANGUAGE_ENGLISH_CAN: + case LANGUAGE_ENGLISH_NZ: + case LANGUAGE_ENGLISH_EIRE: + case LANGUAGE_ENGLISH_SAFRICA: + case LANGUAGE_ENGLISH_JAMAICA: + case LANGUAGE_ENGLISH_CARRIBEAN: + nRet &= ~(ChgQuotes|ChgSglQuotes); + break; + } + return nRet; +} + + +SvxAutoCorrect::SvxAutoCorrect( const String& rShareAutocorrFile, + const String& rUserAutocorrFile ) + : sShareAutoCorrFile( rShareAutocorrFile ), + sUserAutoCorrFile( rUserAutocorrFile ), + pLangTable( new SvxAutoCorrLanguageTable_Impl ), + pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ), + pCharClass( 0 ), bRunNext( false ), + cStartDQuote( 0 ), cEndDQuote( 0 ), cStartSQuote( 0 ), cEndSQuote( 0 ) +{ + nFlags = SvxAutoCorrect::GetDefaultFlags(); + + cEmDash = ByteString::ConvertToUnicode( '\x97', RTL_TEXTENCODING_MS_1252 ); + cEnDash = ByteString::ConvertToUnicode( '\x96', RTL_TEXTENCODING_MS_1252 ); +} + +SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect& rCpy ) +: sShareAutoCorrFile( rCpy.sShareAutoCorrFile ), + sUserAutoCorrFile( rCpy.sUserAutoCorrFile ), + + aSwFlags( rCpy.aSwFlags ), + + pLangTable( new SvxAutoCorrLanguageTable_Impl ), + pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ), + pCharClass( 0 ), bRunNext( false ), + + nFlags( rCpy.nFlags & ~(ChgWordLstLoad|CplSttLstLoad|WrdSttLstLoad)), + cStartDQuote( rCpy.cStartDQuote ), cEndDQuote( rCpy.cEndDQuote ), + cStartSQuote( rCpy.cStartSQuote ), cEndSQuote( rCpy.cEndSQuote ), + cEmDash( rCpy.cEmDash ), cEnDash( rCpy.cEnDash ) +{ +} + + +SvxAutoCorrect::~SvxAutoCorrect() +{ + lcl_ClearTable(*pLangTable); + delete pLangTable; + delete pLastFileTable; + delete pCharClass; +} + +void SvxAutoCorrect::_GetCharClass( LanguageType eLang ) +{ + delete pCharClass; + pCharClass = new CharClass( SvxCreateLocale( eLang )); + eCharClassLang = eLang; +} + +void SvxAutoCorrect::SetAutoCorrFlag( long nFlag, BOOL bOn ) +{ + long nOld = nFlags; + nFlags = bOn ? nFlags | nFlag + : nFlags & ~nFlag; + + if( !bOn ) + { + if( (nOld & CptlSttSntnc) != (nFlags & CptlSttSntnc) ) + nFlags &= ~CplSttLstLoad; + if( (nOld & CptlSttWrd) != (nFlags & CptlSttWrd) ) + nFlags &= ~WrdSttLstLoad; + if( (nOld & Autocorrect) != (nFlags & Autocorrect) ) + nFlags &= ~ChgWordLstLoad; + } +} + + + // Zwei Grossbuchstaben am Wort-Anfang ?? +BOOL SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + BOOL bRet = FALSE; + CharClass& rCC = GetCharClass( eLang ); + + // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und + // teste dann ( erkennt: "(min.", "/min.", usw.) + for( ; nSttPos < nEndPos; ++nSttPos ) + if( rCC.isLetterNumeric( rTxt, nSttPos )) + break; + for( ; nSttPos < nEndPos; --nEndPos ) + if( rCC.isLetterNumeric( rTxt, nEndPos - 1 )) + break; + + // Zwei Grossbuchstaben am Wort-Anfang ?? + if( nSttPos+2 < nEndPos && + IsUpperLetter( rCC.getCharacterType( rTxt, nSttPos )) && + IsUpperLetter( rCC.getCharacterType( rTxt, ++nSttPos )) && + // ist das 3. Zeichen ein klein geschiebenes Alpha-Zeichen + IsLowerLetter( rCC.getCharacterType( rTxt, nSttPos +1 )) && + // keine Sonder-Attribute ersetzen + 0x1 != rTxt.GetChar( nSttPos ) && 0x2 != rTxt.GetChar( nSttPos )) + { + // teste ob das Wort in einer Ausnahmeliste steht + String sWord( rTxt.Copy( nSttPos - 1, nEndPos - nSttPos + 1 )); + if( !FindInWrdSttExceptList(eLang, sWord) ) + { + sal_Unicode cSave = rTxt.GetChar( nSttPos ); + String sChar( cSave ); + rCC.toLower( sChar ); + if( sChar.GetChar(0) != cSave && rDoc.Replace( nSttPos, sChar )) + { + if( SaveWordWrdSttLst & nFlags ) + rDoc.SaveCpltSttWord( CptlSttWrd, nSttPos, sWord, cSave ); + bRet = TRUE; + } + } + } + return bRet; +} + + +BOOL SvxAutoCorrect::FnChgOrdinalNumber( + SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ +// 1st, 2nd, 3rd, 4 - 0th +// 201th oder 201st +// 12th oder 12nd + CharClass& rCC = GetCharClass( eLang ); + BOOL bChg = FALSE; + + for( ; nSttPos < nEndPos; ++nSttPos ) + if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) )) + break; + for( ; nSttPos < nEndPos; --nEndPos ) + if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) )) + break; + + if( 2 < nEndPos - nSttPos && + rCC.isDigit( rTxt, nEndPos - 3 ) ) + { + static sal_Char __READONLY_DATA + sAll[] = "th", /* rest */ + sFirst[] = "st", /* 1 */ + sSecond[] = "nd", /* 2 */ + sThird[] = "rd"; /* 3 */ + static const sal_Char* __READONLY_DATA aNumberTab[ 4 ] = + { + sAll, sFirst, sSecond, sThird + }; + + sal_Unicode c = rTxt.GetChar( nEndPos - 3 ); + if( ( c -= '0' ) > 3 ) + c = 0; + + bChg = ( ((sal_Unicode)*((aNumberTab[ c ])+0)) == + rTxt.GetChar( nEndPos - 2 ) && + ((sal_Unicode)*((aNumberTab[ c ])+1)) == + rTxt.GetChar( nEndPos - 1 )) || + ( 3 < nEndPos - nSttPos && + ( ((sal_Unicode)*(sAll+0)) == rTxt.GetChar( nEndPos - 2 ) && + ((sal_Unicode)*(sAll+1)) == rTxt.GetChar( nEndPos - 1 ))); + + if( bChg ) + { + // dann pruefe mal, ob alle bis zum Start alle Zahlen sind + for( xub_StrLen n = nEndPos - 3; nSttPos < n; ) + if( !rCC.isDigit( rTxt, --n ) ) + { + bChg = !rCC.isLetter( rTxt, n ); + break; + } + + if( bChg ) // dann setze mal das Escapement Attribut + { + SvxEscapementItem aSvxEscapementItem( DFLT_ESC_AUTO_SUPER, + DFLT_ESC_PROP, SID_ATTR_CHAR_ESCAPEMENT ); + rDoc.SetAttr( nEndPos - 2, nEndPos, + SID_ATTR_CHAR_ESCAPEMENT, + aSvxEscapementItem); + } + } + + } + return bChg; +} + + +BOOL SvxAutoCorrect::FnChgToEnEmDash( + SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + BOOL bRet = FALSE; + CharClass& rCC = GetCharClass( eLang ); + if (eLang == LANGUAGE_SYSTEM) + eLang = GetAppLang(); + bool bAlwaysUseEmDash = (cEmDash && (eLang == LANGUAGE_RUSSIAN || eLang == LANGUAGE_UKRAINIAN)); + + // ersetze " - " oder " --" durch "enDash" + if( cEnDash && 1 < nSttPos && 1 <= nEndPos - nSttPos ) + { + sal_Unicode cCh = rTxt.GetChar( nSttPos ); + if( '-' == cCh ) + { + if( ' ' == rTxt.GetChar( nSttPos-1 ) && + '-' == rTxt.GetChar( nSttPos+1 )) + { + xub_StrLen n; + for( n = nSttPos+2; n < nEndPos && lcl_IsInAsciiArr( + sImplSttSkipChars,(cCh = rTxt.GetChar( n ))); + ++n ) + ; + + // found: " --[<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh ) ) + { + for( n = nSttPos-1; n && lcl_IsInAsciiArr( + sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); ) + ; + + // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh )) + { + rDoc.Delete( nSttPos, nSttPos + 2 ); + rDoc.Insert( nSttPos, bAlwaysUseEmDash ? cEmDash : cEnDash ); + bRet = TRUE; + } + } + } + } + else if( 3 < nSttPos && + ' ' == rTxt.GetChar( nSttPos-1 ) && + '-' == rTxt.GetChar( nSttPos-2 )) + { + xub_StrLen n, nLen = 1, nTmpPos = nSttPos - 2; + if( '-' == ( cCh = rTxt.GetChar( nTmpPos-1 )) ) + { + --nTmpPos; + ++nLen; + cCh = rTxt.GetChar( nTmpPos-1 ); + } + if( ' ' == cCh ) + { + for( n = nSttPos; n < nEndPos && lcl_IsInAsciiArr( + sImplSttSkipChars,(cCh = rTxt.GetChar( n ))); + ++n ) + ; + + // found: " - [<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh ) ) + { + cCh = ' '; + for( n = nTmpPos-1; n && lcl_IsInAsciiArr( + sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); ) + ; + // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh )) + { + rDoc.Delete( nTmpPos, nTmpPos + nLen ); + rDoc.Insert( nTmpPos, bAlwaysUseEmDash ? cEmDash : cEnDash ); + bRet = TRUE; + } + } + } + } + } + + // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash". + // Finnish and Hungarian use enDash instead of emDash. + bool bEnDash = (eLang == LANGUAGE_HUNGARIAN || eLang == LANGUAGE_FINNISH); + if( ((cEmDash && !bEnDash) || (cEnDash && bEnDash)) && 4 <= nEndPos - nSttPos ) + { + String sTmp( rTxt.Copy( nSttPos, nEndPos - nSttPos ) ); + xub_StrLen nFndPos = sTmp.SearchAscii( "--" ); + if( STRING_NOTFOUND != nFndPos && nFndPos && + nFndPos + 2 < sTmp.Len() && + ( rCC.isLetterNumeric( sTmp, nFndPos - 1 ) || + lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nFndPos - 1 ) )) && + ( rCC.isLetterNumeric( sTmp, nFndPos + 2 ) || + lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nFndPos + 2 ) ))) + { + nSttPos = nSttPos + nFndPos; + rDoc.Delete( nSttPos, nSttPos + 2 ); + rDoc.Insert( nSttPos, (bEnDash ? cEnDash : cEmDash) ); + bRet = TRUE; + } + } + return bRet; +} + +BOOL SvxAutoCorrect::FnAddNonBrkSpace( + SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen, xub_StrLen nEndPos, + LanguageType eLang ) +{ + bool bRet = false; + + CharClass& rCC = GetCharClass( eLang ); + const lang::Locale rLocale = rCC.getLocale( ); + + if ( rLocale.Language == OUString::createFromAscii( "fr" ) ) + { + bool bFrCA = rLocale.Country == OUString::createFromAscii( "CA" ); + OUString allChars = OUString::createFromAscii( ":;!?" ); + OUString chars( allChars ); + if ( bFrCA ) + chars = OUString::createFromAscii( ":" ); + + sal_Unicode cChar = rTxt.GetChar( nEndPos ); + bool bHasSpace = chars.indexOf( sal_Unicode( cChar ) ) != -1; + bool bIsSpecial = allChars.indexOf( sal_Unicode( cChar ) ) != -1; + if ( bIsSpecial ) + { + // Get the last word delimiter position + xub_StrLen nSttWdPos = nEndPos; + while( nSttWdPos && !IsWordDelim( rTxt.GetChar( --nSttWdPos ))) + ; + + // Check the presence of "://" in the word + xub_StrLen nStrPos = rTxt.Search( String::CreateFromAscii( "://" ), nSttWdPos + 1 ); + if ( STRING_NOTFOUND == nStrPos && nEndPos > 0 ) + { + // Check the previous char + sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 ); + if ( ( chars.indexOf( sal_Unicode( cPrevChar ) ) == -1 ) && cPrevChar != '\t' ) + { + // Remove any previous normal space + xub_StrLen nPos = nEndPos - 1; + while ( cPrevChar == ' ' || cPrevChar == CHAR_HARDBLANK ) + { + if ( nPos == 0 ) break; + nPos--; + cPrevChar = rTxt.GetChar( nPos ); + } + + if ( nPos != 0 ) + { + nPos++; + if ( nEndPos - nPos > 0 ) + rDoc.Delete( nPos, nEndPos ); + + // Add the non-breaking space at the end pos + if ( bHasSpace ) + rDoc.Insert( nPos, CHAR_HARDBLANK ); + bRunNext = true; + bRet = true; + } + } + else if ( chars.indexOf( sal_Unicode( cPrevChar ) ) != -1 ) + bRunNext = true; + } + } + else if ( cChar == '/' ) + { + // Remove the hardspace right before to avoid formatting URLs + sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 ); + sal_Unicode cMaybeSpaceChar = rTxt.GetChar( nEndPos - 2 ); + if ( cPrevChar == ':' && cMaybeSpaceChar == CHAR_HARDBLANK ) + { + rDoc.Delete( nEndPos - 2, nEndPos - 1 ); + bRet = true; + } + } + } + + return bRet; +} + +BOOL SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + String sURL( URIHelper::FindFirstURLInText( rTxt, nSttPos, nEndPos, + GetCharClass( eLang ) )); + BOOL bRet = 0 != sURL.Len(); + if( bRet ) // also Attribut setzen: + rDoc.SetINetAttr( nSttPos, nEndPos, sURL ); + return bRet; +} + + +BOOL SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen, xub_StrLen nEndPos, + LanguageType eLang ) +{ + // Bedingung: + // Am Anfang: _ oder * hinter Space mit nachfolgenden !Space + // Am Ende: _ oder * vor Space (Worttrenner?) + + sal_Unicode c, cInsChar = rTxt.GetChar( nEndPos ); // unterstreichen oder fett + if( ++nEndPos != rTxt.Len() && + !IsWordDelim( rTxt.GetChar( nEndPos ) ) ) + return FALSE; + + --nEndPos; + + BOOL bAlphaNum = FALSE; + xub_StrLen nPos = nEndPos, nFndPos = STRING_NOTFOUND; + CharClass& rCC = GetCharClass( eLang ); + + while( nPos ) + { + switch( c = rTxt.GetChar( --nPos ) ) + { + case '_': + case '*': + if( c == cInsChar ) + { + if( bAlphaNum && nPos+1 < nEndPos && ( !nPos || + IsWordDelim( rTxt.GetChar( nPos-1 ))) && + !IsWordDelim( rTxt.GetChar( nPos+1 ))) + nFndPos = nPos; + else + // Bedingung ist nicht erfuellt, also abbrechen + nFndPos = STRING_NOTFOUND; + nPos = 0; + } + break; + default: + if( !bAlphaNum ) + bAlphaNum = rCC.isLetterNumeric( rTxt, nPos ); + } + } + + if( STRING_NOTFOUND != nFndPos ) + { + // ueber den gefundenen Bereich das Attribut aufspannen und + // das gefunde und am Ende stehende Zeichen loeschen + if( '*' == cInsChar ) // Fett + { + SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT ); + rDoc.SetAttr( nFndPos + 1, nEndPos, + SID_ATTR_CHAR_WEIGHT, + aSvxWeightItem); + } + else // unterstrichen + { + SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE ); + rDoc.SetAttr( nFndPos + 1, nEndPos, + SID_ATTR_CHAR_UNDERLINE, + aSvxUnderlineItem); + } + rDoc.Delete( nEndPos, nEndPos + 1 ); + rDoc.Delete( nFndPos, nFndPos + 1 ); + } + + return STRING_NOTFOUND != nFndPos; +} + + +BOOL SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc& rDoc, + const String& rTxt, BOOL bNormalPos, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + // Grossbuchstabe am Satz-Anfang ?? + if( !rTxt.Len() || nEndPos <= nSttPos ) + return FALSE; + + CharClass& rCC = GetCharClass( eLang ); + String aText( rTxt ); + const sal_Unicode *pStart = aText.GetBuffer(), + *pStr = pStart + nEndPos, + *pWordStt = 0, + *pDelim = 0; + + BOOL bAtStart = FALSE, bPrevPara = FALSE; + do { + --pStr; + if( rCC.isLetter( + aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ) + { + if( !pWordStt ) + pDelim = pStr+1; + pWordStt = pStr; + } + else if( pWordStt && + !rCC.isDigit( + aText, + sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ) + { + if( lcl_IsInAsciiArr( sImplWordChars, *pStr ) && + pWordStt - 1 == pStr && + // --> FME 2005-02-14 #i38971# + // l'intallazione at beginning of paragraph. Replaced < by <= + (long)(pStart + 1) <= (long)pStr && + // <-- + rCC.isLetter( + aText, + sal::static_int_cast< xub_StrLen >( pStr-1 - pStart ) ) ) + pWordStt = --pStr; + else + break; + } + } while( 0 == ( bAtStart = (pStart == pStr)) ); + + + if( !pWordStt || + rCC.isDigit( + aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) || + IsUpperLetter( + rCC.getCharacterType( + aText, + sal::static_int_cast< xub_StrLen >( pWordStt - pStart ) ) ) || + 0x1 == *pWordStt || 0x2 == *pWordStt ) + return FALSE; // kein zu ersetzendes Zeichen, oder schon ok + + // JP 27.10.97: wenn das Wort weniger als 3 Zeichen hat und der Trenner + // ein "Num"-Trenner ist, dann nicht ersetzen! + // Damit wird ein "a.", "a)", "a-a" nicht ersetzt! + if( *pDelim && 2 >= pDelim - pWordStt && + lcl_IsInAsciiArr( ".-)>", *pDelim ) ) + return FALSE; + + if( !bAtStart ) // noch kein Absatz Anfang ? + { + if ( IsWordDelim( *pStr ) ) + { + while( 0 == ( bAtStart = (pStart == pStr--) ) && IsWordDelim( *pStr )) + ; + } + // Asian full stop, full width full stop, full width exclamation mark + // and full width question marks are treated as word delimiters + else if ( 0x3002 != *pStr && 0xFF0E != *pStr && 0xFF01 != *pStr && + 0xFF1F != *pStr ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + } + + if( bAtStart ) // am Absatz Anfang ? + { + // Ueberpruefe den vorherigen Absatz, wenn es diesen gibt. + // Wenn ja, dann pruefe auf SatzTrenner am Ende. + const String* pPrevPara = rDoc.GetPrevPara( bNormalPos ); + if( !pPrevPara ) + { + // gueltiger Trenner -> Ersetze + String sChar( *pWordStt ); + rCC.toUpper( sChar ); + return sChar != *pWordStt && + rDoc.Replace( xub_StrLen( pWordStt - pStart ), sChar ); + } + + aText = *pPrevPara; + bPrevPara = TRUE; + bAtStart = FALSE; + pStart = aText.GetBuffer(); + pStr = pStart + aText.Len(); + + do { // alle Blanks ueberlesen + --pStr; + if( !IsWordDelim( *pStr )) + break; + } while( 0 == ( bAtStart = (pStart == pStr)) ); + + if( bAtStart ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + } + + // bis hierhier wurde [ \t]+[A-Z0-9]+ gefunden. Test jetzt auf den + // Satztrenner. Es koennen alle 3 vorkommen, aber nicht mehrfach !! + const sal_Unicode* pExceptStt = 0; + if( !bAtStart ) + { + BOOL bWeiter = TRUE; + int nFlag = C_NONE; + do { + switch( *pStr ) + { + // Western and Asian full stop + case '.': + case 0x3002 : + case 0xFF0E : + { + if( nFlag & C_FULL_STOP ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + nFlag |= C_FULL_STOP; + pExceptStt = pStr; + } + break; + case '!': + case 0xFF01 : + { + if( nFlag & C_EXCLAMATION_MARK ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + nFlag |= C_EXCLAMATION_MARK; + } + break; + case '?': + case 0xFF1F : + { + if( nFlag & C_QUESTION_MARK) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + nFlag |= C_QUESTION_MARK; + } + break; + default: + if( !nFlag ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + else + bWeiter = FALSE; + break; + } + + if( bWeiter && pStr-- == pStart ) + { +// !!! wenn am Anfang, dann nie ersetzen. +// if( !nFlag ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung +// ++pStr; +// break; // Schleife beenden + } + } while( bWeiter ); + if( C_FULL_STOP != nFlag ) + pExceptStt = 0; + } + + if( 2 > ( pStr - pStart ) ) + return FALSE; + + if( !rCC.isLetterNumeric( + aText, sal::static_int_cast< xub_StrLen >( pStr-- - pStart ) ) ) + { + BOOL bValid = FALSE, bAlphaFnd = FALSE; + const sal_Unicode* pTmpStr = pStr; + while( !bValid ) + { + if( rCC.isDigit( + aText, + sal::static_int_cast< xub_StrLen >( pTmpStr - pStart ) ) ) + { + bValid = TRUE; + pStr = pTmpStr - 1; + } + else if( rCC.isLetter( + aText, + sal::static_int_cast< xub_StrLen >( + pTmpStr - pStart ) ) ) + { + if( bAlphaFnd ) + { + bValid = TRUE; + pStr = pTmpStr; + } + else + bAlphaFnd = TRUE; + } + else if( bAlphaFnd || IsWordDelim( *pTmpStr ) ) + break; + + if( pTmpStr == pStart ) + break; + + --pTmpStr; + } + + if( !bValid ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + } + + BOOL bNumericOnly = '0' <= *(pStr+1) && *(pStr+1) <= '9'; + + // suche den Anfang vom Wort + while( !IsWordDelim( *pStr )) + { + if( bNumericOnly && + rCC.isLetter( + aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ) + bNumericOnly = FALSE; + + if( pStart == pStr ) + break; + + --pStr; + } + + if( bNumericOnly ) // besteht nur aus Zahlen, dann nicht + return FALSE; + + if( IsWordDelim( *pStr )) + ++pStr; + + String sWord; + + // ueberpruefe anhand der Exceptionliste + if( pExceptStt ) + { + sWord = String( + pStr, sal::static_int_cast< xub_StrLen >( pExceptStt - pStr + 1 ) ); + if( FindInCplSttExceptList(eLang, sWord) ) + return FALSE; + + // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und + // teste dann noch mal ( erkennt: "(min.", "/min.", usw.) + String sTmp( sWord ); + while( sTmp.Len() && + !rCC.isLetterNumeric( sTmp, 0 ) ) + sTmp.Erase( 0, 1 ); + + // alle hinteren nicht alphanumerische Zeichen bis auf das + // Letzte entfernen + xub_StrLen nLen = sTmp.Len(); + while( nLen && !rCC.isLetterNumeric( sTmp, nLen-1 ) ) + --nLen; + if( nLen + 1 < sTmp.Len() ) + sTmp.Erase( nLen + 1 ); + + if( sTmp.Len() && sTmp.Len() != sWord.Len() && + FindInCplSttExceptList(eLang, sTmp)) + return FALSE; + + if(FindInCplSttExceptList(eLang, sWord, TRUE)) + return FALSE; + } + + // Ok, dann ersetze mal + sal_Unicode cSave = *pWordStt; + nSttPos = sal::static_int_cast< xub_StrLen >( pWordStt - rTxt.GetBuffer() ); + String sChar( cSave ); + rCC.toUpper( sChar ); + BOOL bRet = sChar.GetChar(0) != cSave && rDoc.Replace( nSttPos, sChar ); + + // das Wort will vielleicht jemand haben + if( bRet && SaveWordCplSttLst & nFlags ) + rDoc.SaveCpltSttWord( CptlSttSntnc, nSttPos, sWord, cSave ); + + return bRet; +} +//The method below is renamed from _GetQuote to GetQuote by BerryJia for Bug95846 Time:2002-8-13 15:50 +sal_Unicode SvxAutoCorrect::GetQuote( sal_Unicode cInsChar, BOOL bSttQuote, + LanguageType eLang ) const +{ + sal_Unicode cRet = bSttQuote ? ( '\"' == cInsChar + ? GetStartDoubleQuote() + : GetStartSingleQuote() ) + : ( '\"' == cInsChar + ? GetEndDoubleQuote() + : GetEndSingleQuote() ); + if( !cRet ) + { + // dann ueber die Language das richtige Zeichen heraussuchen + if( LANGUAGE_NONE == eLang ) + cRet = cInsChar; + else + { + LocaleDataWrapper& rLcl = GetLocaleDataWrapper( eLang ); + String sRet( bSttQuote + ? ( '\"' == cInsChar + ? rLcl.getDoubleQuotationMarkStart() + : rLcl.getQuotationMarkStart() ) + : ( '\"' == cInsChar + ? rLcl.getDoubleQuotationMarkEnd() + : rLcl.getQuotationMarkEnd() )); + cRet = sRet.Len() ? sRet.GetChar( 0 ) : cInsChar; + } + } + return cRet; +} + +void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos, + sal_Unicode cInsChar, BOOL bSttQuote, + BOOL bIns ) +{ + LanguageType eLang = rDoc.GetLanguage( nInsPos, FALSE ); + sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang ); + + //JP 13.02.99: damit beim Undo das "einfuegte" Zeichen wieder erscheint, + // wird es erstmal eingefuegt und dann ueberschrieben + String sChg( cInsChar ); + if( bIns ) + rDoc.Insert( nInsPos, sChg ); + else + rDoc.Replace( nInsPos, sChg ); + + //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei + // franzoesischer Sprache an Anfang ein Leerzeichen dahinter + // und am Ende ein Leerzeichen dahinter eingefuegt werden. + sChg = cRet; + + if( '\"' == cInsChar ) + { + if( LANGUAGE_SYSTEM == eLang ) + eLang = GetAppLang(); + switch( eLang ) + { + case LANGUAGE_FRENCH: + case LANGUAGE_FRENCH_BELGIAN: + case LANGUAGE_FRENCH_CANADIAN: + case LANGUAGE_FRENCH_SWISS: + case LANGUAGE_FRENCH_LUXEMBOURG: + // JP 09.02.99: das zusaetzliche Zeichen immer per Insert einfuegen. + // Es ueberschreibt nichts! + { + String s( static_cast< sal_Unicode >(0xA0) ); + // UNICODE code for no break space + if( rDoc.Insert( bSttQuote ? nInsPos+1 : nInsPos, s )) + { + if( !bSttQuote ) + ++nInsPos; + } + } + break; + } + } + + rDoc.Replace( nInsPos, sChg ); +} + +String SvxAutoCorrect::GetQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos, + sal_Unicode cInsChar, BOOL bSttQuote ) +{ + LanguageType eLang = rDoc.GetLanguage( nInsPos, FALSE ); + sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang ); + + String sRet( cRet ); + //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei + // franzoesischer Sprache an Anfang ein Leerzeichen dahinter + // und am Ende ein Leerzeichen dahinter eingefuegt werden. + if( '\"' == cInsChar ) + { + if( LANGUAGE_SYSTEM == eLang ) + eLang = GetAppLang(); + switch( eLang ) + { + case LANGUAGE_FRENCH: + case LANGUAGE_FRENCH_BELGIAN: + case LANGUAGE_FRENCH_CANADIAN: + case LANGUAGE_FRENCH_SWISS: + case LANGUAGE_FRENCH_LUXEMBOURG: + if( bSttQuote ) + sRet += ' '; + else + sRet.Insert( ' ', 0 ); + break; + } + } + return sRet; +} + +ULONG SvxAutoCorrect::AutoCorrect( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nInsPos, sal_Unicode cChar, + BOOL bInsert ) +{ + ULONG nRet = 0; + bool bIsNextRun = bRunNext; + bRunNext = false; // if it was set, then it has to be turned off + + do{ // only for middle check loop !! + if( cChar ) + { + //JP 10.02.97: doppelte Spaces verhindern + if( nInsPos && ' ' == cChar && + IsAutoCorrFlag( IgnoreDoubleSpace ) && + ' ' == rTxt.GetChar( nInsPos - 1 ) ) + { + nRet = IgnoreDoubleSpace; + break; + } + + BOOL bSingle = '\'' == cChar; + BOOL bIsReplaceQuote = + (IsAutoCorrFlag( ChgQuotes ) && ('\"' == cChar )) || + (IsAutoCorrFlag( ChgSglQuotes ) && bSingle ); + if( bIsReplaceQuote ) + { + sal_Unicode cPrev; + BOOL bSttQuote = !nInsPos || + IsWordDelim( ( cPrev = rTxt.GetChar( nInsPos-1 ))) || +// os: #56034# - Warum kein schliessendes Anfuehrungszeichen nach dem Bindestrich? +// strchr( "-([{", cPrev ) || + lcl_IsInAsciiArr( "([{", cPrev ) || + ( cEmDash && cEmDash == cPrev ) || + ( cEnDash && cEnDash == cPrev ); + + InsertQuote( rDoc, nInsPos, cChar, bSttQuote, bInsert ); + nRet = bSingle ? ChgSglQuotes : ChgQuotes; + break; + } + + if( bInsert ) + rDoc.Insert( nInsPos, cChar ); + else + rDoc.Replace( nInsPos, cChar ); + + // Hardspaces autocorrection + if ( IsAutoCorrFlag( AddNonBrkSpace ) ) + { + if ( NeedsHardspaceAutocorr( cChar ) && + FnAddNonBrkSpace( rDoc, rTxt, 0, nInsPos, rDoc.GetLanguage( nInsPos, FALSE ) ) ) + { + nRet = AddNonBrkSpace; + } + else if ( bIsNextRun && !IsAutoCorrectChar( cChar ) ) + { + // Remove the NBSP if it wasn't an autocorrection + if ( NeedsHardspaceAutocorr( rTxt.GetChar( nInsPos - 1 ) ) && + cChar != ' ' && cChar != '\t' && cChar != CHAR_HARDBLANK ) + { + // Look for the last HARD_SPACE + xub_StrLen nPos = nInsPos - 1; + bool bFound = false; + while ( nPos != STRING_NOTFOUND && !bFound ) + { + sal_Unicode cTmpChar = rTxt.GetChar( nPos ); + if ( cTmpChar == CHAR_HARDBLANK ) + bFound = true; + else if ( !NeedsHardspaceAutocorr( cTmpChar ) ) + nPos = STRING_NOTFOUND; + nPos--; + } + + if ( bFound && nPos != STRING_NOTFOUND ) + { + rDoc.Delete( nPos + 1, nPos + 2 ); + nRet = AddNonBrkSpace; + } + } + } + } + } + + if( !nInsPos ) + break; + + xub_StrLen nPos = nInsPos - 1; + + // Bug 19286: nur direkt hinter dem "Wort" aufsetzen + if( IsWordDelim( rTxt.GetChar( nPos ))) + break; + + // automatisches Fett oder Unterstreichen setzen? + if( '*' == cChar || '_' == cChar ) + { + if( IsAutoCorrFlag( ChgWeightUnderl ) && + FnChgWeightUnderl( rDoc, rTxt, 0, nPos+1 ) ) + nRet = ChgWeightUnderl; + break; + } + + while( nPos && !IsWordDelim( rTxt.GetChar( --nPos ))) + ; + + // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort + // Kuerzel im Auto + xub_StrLen nCapLttrPos = nPos+1; // auf das 1. Zeichen + if( !nPos && !IsWordDelim( rTxt.GetChar( 0 ))) + --nCapLttrPos; // Absatz Anfang und kein Blank ! + + LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, FALSE ); + if( LANGUAGE_SYSTEM == eLang ) + eLang = MsLangId::getSystemLanguage(); + CharClass& rCC = GetCharClass( eLang ); + + // Bug 19285: Symbolzeichen nicht anfassen + if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nInsPos )) + break; + + if( IsAutoCorrFlag( Autocorrect ) ) + { + const String* pPara = 0; + const String** ppPara = IsAutoCorrFlag(CptlSttSntnc) ? &pPara : 0; + + BOOL bChgWord = rDoc.ChgAutoCorrWord( nCapLttrPos, nInsPos, + *this, ppPara ); + if( !bChgWord ) + { + // JP 16.06.98: dann versuche mal alle !AlphaNum. Zeichen los zu + // werden und teste dann nochmals + //JP 22.04.99: Bug 63883 - entferne nur die "Klammern Start/-Anfaenge", + // alle anderen Zeichen muessen drin bleiben. + xub_StrLen nCapLttrPos1 = nCapLttrPos, nInsPos1 = nInsPos; + while( nCapLttrPos1 < nInsPos && + lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos1 ) ) + ) + ++nCapLttrPos1; + while( nCapLttrPos1 < nInsPos1 && nInsPos1 && + lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nInsPos1-1 ) ) + ) + --nInsPos1; + + if( (nCapLttrPos1 != nCapLttrPos || nInsPos1 != nInsPos ) && + nCapLttrPos1 < nInsPos1 && + rDoc.ChgAutoCorrWord( nCapLttrPos1, nInsPos1, *this, ppPara )) + { + bChgWord = TRUE; + nCapLttrPos = nCapLttrPos1; + } + } + + if( bChgWord ) + { + nRet = Autocorrect; + if( pPara ) + { + xub_StrLen nEnd = nCapLttrPos; + while( nEnd < pPara->Len() && + !IsWordDelim( pPara->GetChar( nEnd ))) + ++nEnd; + + // Grossbuchstabe am Satz-Anfang ?? + if( IsAutoCorrFlag( CptlSttSntnc ) && + FnCptlSttSntnc( rDoc, *pPara, FALSE, + nCapLttrPos, nEnd, eLang ) ) + nRet |= CptlSttSntnc; + + if( IsAutoCorrFlag( ChgToEnEmDash ) && + FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nEnd, eLang ) ) + nRet |= ChgToEnEmDash; + } + break; + } + } + + if( ( IsAutoCorrFlag( nRet = ChgOrdinalNumber ) && + FnChgOrdinalNumber( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) || + ( IsAutoCorrFlag( nRet = SetINetAttr ) && + ( ' ' == cChar || '\t' == cChar || 0x0a == cChar || !cChar ) && + FnSetINetAttr( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) ) + ; + else + { + nRet = 0; + // Grossbuchstabe am Satz-Anfang ?? + if( IsAutoCorrFlag( CptlSttSntnc ) && + FnCptlSttSntnc( rDoc, rTxt, TRUE, nCapLttrPos, nInsPos, eLang ) ) + nRet |= CptlSttSntnc; + + // Zwei Grossbuchstaben am Wort-Anfang ?? + if( IsAutoCorrFlag( CptlSttWrd ) && + FnCptlSttWrd( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) + nRet |= CptlSttWrd; + + if( IsAutoCorrFlag( ChgToEnEmDash ) && + FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) + nRet |= ChgToEnEmDash; + } + + } while( FALSE ); + + if( nRet ) + { + ULONG nHelpId = 0; + if( nRet & ( Autocorrect|CptlSttSntnc|CptlSttWrd|ChgToEnEmDash ) ) + { + // von 0 - 15 + if( nRet & ChgToEnEmDash ) + nHelpId += 8; + if( nRet & Autocorrect ) + nHelpId += 4; + if( nRet & CptlSttSntnc ) + nHelpId += 2; + if( nRet & CptlSttWrd ) + nHelpId += 1; + } + else + { + if( nRet & ChgQuotes) nHelpId = 16; + else if( nRet & ChgSglQuotes) nHelpId = 17; + else if( nRet & SetINetAttr) nHelpId = 18; + else if( nRet & IgnoreDoubleSpace) nHelpId = 19; + else if( nRet & ChgWeightUnderl) nHelpId = 20; + else if( nRet & AddNonBrkSpace) nHelpId = 21; + else if( nRet & ChgOrdinalNumber) nHelpId = 22; + } + + if( nHelpId ) + { + nHelpId += HID_AUTOCORR_HELP_START - 1; + Application::GetHelp()->OpenHelpAgent( nHelpId ); + } + } + + + return nRet; +} + +SvxAutoCorrectLanguageLists& SvxAutoCorrect::_GetLanguageList( + LanguageType eLang ) +{ + if( !pLangTable->IsKeyValid( ULONG( eLang ))) + CreateLanguageFile( eLang, TRUE); + return *pLangTable->Seek( ULONG( eLang ) ); +} + +void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang ) +{ + if( pLangTable->IsKeyValid( ULONG( eLang ))) + { + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang)); + if( pLists ) + pLists->SaveCplSttExceptList(); + } +#ifdef DBG_UTIL + else + { + DBG_ERROR("speichern einer leeren Liste?"); + } +#endif +} + +void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang) +{ + if(pLangTable->IsKeyValid(ULONG(eLang))) + { + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang)); + if(pLists) + pLists->SaveWrdSttExceptList(); + } +#ifdef DBG_UTIL + else + { + DBG_ERROR("speichern einer leeren Liste?"); + } +#endif +} + + + // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort + // in die Datei geschrieben! +BOOL SvxAutoCorrect::AddCplSttException( const String& rNew, + LanguageType eLang ) +{ + SvxAutoCorrectLanguageListsPtr pLists = 0; + //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste + if( pLangTable->IsKeyValid(ULONG(eLang))) + pLists = pLangTable->Seek(ULONG(eLang)); + else if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| + CreateLanguageFile(LANGUAGE_DONTKNOW, TRUE)) + { + pLists = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + } + DBG_ASSERT(pLists, "keine Autokorrekturdatei"); + return pLists->AddToCplSttExceptList(rNew); +} + + + // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort + // in die Datei geschrieben! +BOOL SvxAutoCorrect::AddWrtSttException( const String& rNew, + LanguageType eLang ) +{ + SvxAutoCorrectLanguageListsPtr pLists = 0; + //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste + if(pLangTable->IsKeyValid(ULONG(eLang))) + pLists = pLangTable->Seek(ULONG(eLang)); + else if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| + CreateLanguageFile(LANGUAGE_DONTKNOW, TRUE)) + pLists = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + DBG_ASSERT(pLists, "keine Autokorrekturdatei"); + return pLists->AddToWrdSttExceptList(rNew); +} + + + + +void SvxAutoCorrect::SetUserAutoCorrFileName( const String& rNew ) +{ + if( sUserAutoCorrFile != rNew ) + { + sUserAutoCorrFile = rNew; + + // sind die Listen gesetzt sind, so muessen sie jetzt geloescht + // werden + lcl_ClearTable(*pLangTable); + nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad ); + } +} + +void SvxAutoCorrect::SetShareAutoCorrFileName( const String& rNew ) +{ + if( sShareAutoCorrFile != rNew ) + { + sShareAutoCorrFile = rNew; + + // sind die Listen gesetzt sind, so muessen sie jetzt geloescht + // werden + lcl_ClearTable(*pLangTable); + nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad ); + } +} + + +BOOL SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc& rDoc, + const String& rTxt, xub_StrLen nPos, + String& rWord ) const +{ + if( !nPos ) + return FALSE; + + xub_StrLen nEnde = nPos; + + // dahinter muss ein Blank oder Tab folgen! + if( ( nPos < rTxt.Len() && + !IsWordDelim( rTxt.GetChar( nPos ))) || + IsWordDelim( rTxt.GetChar( --nPos ))) + return FALSE; + + while( nPos && !IsWordDelim( rTxt.GetChar( --nPos ))) + ; + + // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort + // Kuerzel im Auto + xub_StrLen nCapLttrPos = nPos+1; // auf das 1. Zeichen + if( !nPos && !IsWordDelim( rTxt.GetChar( 0 ))) + --nCapLttrPos; // Absatz Anfang und kein Blank ! + + while( lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos )) ) + if( ++nCapLttrPos >= nEnde ) + return FALSE; + + // Bug 19285: Symbolzeichen nicht anfassen + // Interresant erst ab 3 Zeichen + if( 3 > nEnde - nCapLttrPos ) + return FALSE; + + LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, FALSE ); + if( LANGUAGE_SYSTEM == eLang ) + eLang = MsLangId::getSystemLanguage(); + + SvxAutoCorrect* pThis = (SvxAutoCorrect*)this; + CharClass& rCC = pThis->GetCharClass( eLang ); + + if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nEnde )) + return FALSE; + + rWord = rTxt.Copy( nCapLttrPos, nEnde - nCapLttrPos ); + return TRUE; +} + +BOOL SvxAutoCorrect::CreateLanguageFile( LanguageType eLang, BOOL bNewFile ) +{ + DBG_ASSERT(!pLangTable->IsKeyValid(ULONG(eLang)), "Sprache ist bereits vorhanden"); + + String sUserDirFile( GetAutoCorrFileName( eLang, TRUE, FALSE )), + sShareDirFile( sUserDirFile ); + SvxAutoCorrectLanguageListsPtr pLists = 0; + + Time nMinTime( 0, 2 ), nAktTime, nLastCheckTime; + ULONG nFndPos; + if( TABLE_ENTRY_NOTFOUND != + pLastFileTable->SearchKey( ULONG( eLang ), &nFndPos ) && + ( nLastCheckTime.SetTime( pLastFileTable->GetObject( nFndPos )), + nLastCheckTime < nAktTime ) && + ( nAktTime - nLastCheckTime ) < nMinTime ) + { + // no need to test the file, because the last check is not older then + // 2 minutes. + if( bNewFile ) + { + sShareDirFile = sUserDirFile; + pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, + sUserDirFile, eLang ); + pLangTable->Insert( ULONG(eLang), pLists ); + pLastFileTable->Remove( ULONG( eLang ) ); + } + } + else if( ( FStatHelper::IsDocument( sUserDirFile ) || + FStatHelper::IsDocument( sShareDirFile = + GetAutoCorrFileName( eLang, FALSE, FALSE ) ) ) || + ( sShareDirFile = sUserDirFile, bNewFile )) + { + pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, + sUserDirFile, eLang ); + pLangTable->Insert( ULONG(eLang), pLists ); + pLastFileTable->Remove( ULONG( eLang ) ); + } + else if( !bNewFile ) + { + if( !pLastFileTable->Insert( ULONG( eLang ), nAktTime.GetTime() )) + pLastFileTable->Replace( ULONG( eLang ), nAktTime.GetTime() ); + } + return pLists != 0; +} + +BOOL SvxAutoCorrect::PutText( const String& rShort, const String& rLong, + LanguageType eLang ) +{ + BOOL bRet = FALSE; + if( pLangTable->IsKeyValid( ULONG(eLang)) || CreateLanguageFile(eLang) ) + bRet = pLangTable->Seek( ULONG(eLang) )->PutText(rShort, rLong); + return bRet; +} + + + // - loesche einen Eintrag +BOOL SvxAutoCorrect::DeleteText( const String& rShort, LanguageType eLang ) +{ + BOOL bRet = FALSE; + if( pLangTable->IsKeyValid( ULONG( eLang )) ) + bRet = pLangTable->Seek( ULONG( eLang ))->DeleteText( rShort ); + return bRet; +} + + + // - return den Ersetzungstext (nur fuer SWG-Format, alle anderen + // koennen aus der Wortliste herausgeholt werden!) +BOOL SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String& , String& ) +{ + return FALSE; +} + + // - Text mit Attributierung (kann nur der SWG - SWG-Format!) +BOOL SvxAutoCorrect::PutText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String&, SfxObjectShell&, + String& ) +{ + return FALSE; +} + +void EncryptBlockName_Imp( String& rName ) +{ + xub_StrLen nLen, nPos = 1; + rName.Insert( '#', 0 ); + sal_Unicode* pName = rName.GetBufferAccess(); + for ( nLen = rName.Len(), ++pName; nPos < nLen; ++nPos, ++pName ) + { + if( lcl_IsInAsciiArr( "!/:.\\", *pName )) + *pName &= 0x0f; + } +} + +/* This code is copied from SwXMLTextBlocks::GeneratePackageName */ +void GeneratePackageName ( const String& rShort, String& rPackageName ) +{ + rPackageName = rShort; + xub_StrLen nPos = 0; + sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 }; + ByteString sByte ( rPackageName, RTL_TEXTENCODING_UTF7); + rPackageName = String (sByte, RTL_TEXTENCODING_ASCII_US); + while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos ))) + { + rPackageName.SetChar( nPos, '_' ); + ++nPos; + } +} + +void DecryptBlockName_Imp( String& rName ) +{ + if( '#' == rName.GetChar( 0 ) ) + { + rName.Erase( 0, 1 ); + sal_Unicode* pName = rName.GetBufferAccess(); + xub_StrLen nLen, nPos; + for ( nLen = rName.Len(), nPos = 0; nPos < nLen; ++nPos, ++pName ) + switch( *pName ) + { + case 0x01: *pName = '!'; break; + case 0x0A: *pName = ':'; break; + case 0x0C: *pName = '\\'; break; + case 0x0E: *pName = '.'; break; + case 0x0F: *pName = '/'; break; + } + } +} + + +/* -----------------18.11.98 16:00------------------- + * + * --------------------------------------------------*/ +const SvxAutocorrWord* lcl_SearchWordsInList( + SvxAutoCorrectLanguageListsPtr pList, const String& rTxt, + xub_StrLen& rStt, xub_StrLen nEndPos, SvxAutoCorrDoc& ) +{ + const SvxAutocorrWordList* pAutoCorrWordList = pList->GetAutocorrWordList(); + TransliterationWrapper& rCmp = GetIgnoreTranslWrapper(); + for( xub_StrLen nPos = 0; nPos < pAutoCorrWordList->Count(); ++nPos ) + { + const SvxAutocorrWord* pFnd = (*pAutoCorrWordList)[ nPos ]; + const String& rChk = pFnd->GetShort(); + if( nEndPos >= rChk.Len() ) + { + xub_StrLen nCalcStt = nEndPos - rChk.Len(); + if( ( !nCalcStt || nCalcStt == rStt || + ( nCalcStt < rStt && + IsWordDelim( rTxt.GetChar(nCalcStt - 1 ) ))) ) + { + String sWord( rTxt.GetBuffer() + nCalcStt, rChk.Len() ); + if( rCmp.isEqual( rChk, sWord )) + { + rStt = nCalcStt; + return pFnd; + } + } + } + } + return 0; +} + + +// suche das oder die Worte in der ErsetzungsTabelle +const SvxAutocorrWord* SvxAutoCorrect::SearchWordsInList( + const String& rTxt, xub_StrLen& rStt, xub_StrLen nEndPos, + SvxAutoCorrDoc& rDoc, LanguageType& rLang ) +{ + LanguageType eLang = rLang; + const SvxAutocorrWord* pRet = 0; + if( LANGUAGE_SYSTEM == eLang ) + eLang = MsLangId::getSystemLanguage(); + + // zuerst nach eLang suchen, dann nach der Obersprache + // US-Englisch -> Englisch und zuletzt in LANGUAGE_DONTKNOW + + if( pLangTable->IsKeyValid( ULONG( eLang ) ) || + CreateLanguageFile( eLang, FALSE )) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(eLang)); + pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc ); + if( pRet ) + { + rLang = eLang; + return pRet; + } + } + + // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen + ULONG nTmpKey1 = eLang & 0x7ff, // die Hauptsprache in vielen Faellen u.B. DE + nTmpKey2 = eLang & 0x3ff, // sonst z.B. EN + nTmp; + + if( ((nTmp = nTmpKey1) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey1 ) || + CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) || + (( nTmp = nTmpKey2) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey2 ) || + CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek( nTmp ); + pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc); + if( pRet ) + { + rLang = LanguageType( nTmp ); + return pRet; + } + } + if( pLangTable->IsKeyValid( ULONG( LANGUAGE_DONTKNOW ) ) || + CreateLanguageFile( LANGUAGE_DONTKNOW, FALSE ) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc); + if( pRet ) + { + rLang = LANGUAGE_DONTKNOW; + return pRet; + } + } + return 0; +} +/* -----------------18.11.98 13:46------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang, + const String& sWord ) +{ + //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch + //und zuletzt in LANGUAGE_DONTKNOW + ULONG nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE + ULONG nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN + String sTemp(sWord); + if( pLangTable->IsKeyValid( ULONG( eLang )) || + CreateLanguageFile( eLang, FALSE ) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(eLang)); + String _sTemp(sWord); + if(pList->GetWrdSttExceptList()->Seek_Entry(&_sTemp)) + return TRUE; + + } + // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen + ULONG nTmp; + if( ((nTmp = nTmpKey1) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey1 ) || + CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) || + (( nTmp = nTmpKey2) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey2 ) || + CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(nTmp); + if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp)) + return TRUE; + } + if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, FALSE)) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp)) + return TRUE; + } + return FALSE; +} +/* -----------------18.11.98 14:28------------------- + * + * --------------------------------------------------*/ +BOOL lcl_FindAbbreviation( const SvStringsISortDtor* pList, const String& sWord) +{ + String sAbk( '~' ); + USHORT nPos; + pList->Seek_Entry( &sAbk, &nPos ); + if( nPos < pList->Count() ) + { + String sLowerWord( sWord ); sLowerWord.ToLowerAscii(); + const String* pAbk; + for( USHORT n = nPos; + n < pList->Count() && + '~' == ( pAbk = (*pList)[ n ])->GetChar( 0 ); + ++n ) + { + // ~ und ~. sind nicht erlaubt! + if( 2 < pAbk->Len() && pAbk->Len() - 1 <= sWord.Len() ) + { + String sLowerAbk( *pAbk ); sLowerAbk.ToLowerAscii(); + for( xub_StrLen i = sLowerAbk.Len(), ii = sLowerWord.Len(); i; ) + { + if( !--i ) // stimmt ueberein + return TRUE; + + if( sLowerAbk.GetChar( i ) != sLowerWord.GetChar( --ii )) + break; + } + } + } + } + DBG_ASSERT( !(nPos && '~' == (*pList)[ --nPos ]->GetChar( 0 ) ), + "falsch sortierte ExeptionListe?" ); + return FALSE; +} +/* -----------------18.11.98 14:49------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang, + const String& sWord, BOOL bAbbreviation) +{ + //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch + //und zuletzt in LANGUAGE_DONTKNOW + ULONG nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE + ULONG nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN + String sTemp( sWord ); + if( pLangTable->IsKeyValid( ULONG( eLang )) || + CreateLanguageFile( eLang, FALSE )) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang)); + const SvStringsISortDtor* pList = pLists->GetCplSttExceptList(); + if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord) + : pList->Seek_Entry( &sTemp ) ) + return TRUE; + } + // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen + ULONG nTmp; + + if( ((nTmp = nTmpKey1) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey1 ) || + CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) || + (( nTmp = nTmpKey2) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey2 ) || + CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(nTmp); + const SvStringsISortDtor* pList = pLists->GetCplSttExceptList(); + if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord) + : pList->Seek_Entry( &sTemp ) ) + return TRUE; + } + if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, FALSE)) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(LANGUAGE_DONTKNOW); + const SvStringsISortDtor* pList = pLists->GetCplSttExceptList(); + if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord) + : pList->Seek_Entry( &sTemp ) ) + return TRUE; + } + return FALSE; + +} + +/* -----------------20.11.98 11:53------------------- + * + * --------------------------------------------------*/ +String SvxAutoCorrect::GetAutoCorrFileName( LanguageType eLang, + BOOL bNewFile, BOOL bTst ) const +{ + String sRet, sExt( MsLangId::convertLanguageToIsoString( eLang ) ); + sExt.Insert('_', 0); + sExt.AppendAscii( ".dat" ); + if( bNewFile ) + ( sRet = sUserAutoCorrFile ) += sExt; + else if( !bTst ) + ( sRet = sShareAutoCorrFile ) += sExt; + else + { + // test first in the user directory - if not exist, then + ( sRet = sUserAutoCorrFile ) += sExt; + if( !FStatHelper::IsDocument( sRet )) + ( sRet = sShareAutoCorrFile ) += sExt; + } + return sRet; +} + +/* -----------------18.11.98 11:16------------------- + * + * --------------------------------------------------*/ +SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists( + SvxAutoCorrect& rParent, + const String& rShareAutoCorrectFile, + const String& rUserAutoCorrectFile, + LanguageType eLang) +: sShareAutoCorrFile( rShareAutoCorrectFile ), + sUserAutoCorrFile( rUserAutoCorrectFile ), + eLanguage(eLang), + pCplStt_ExcptLst( 0 ), + pWrdStt_ExcptLst( 0 ), + pAutocorr_List( 0 ), + rAutoCorrect(rParent), + nFlags(0) +{ +} + +/* -----------------18.11.98 11:16------------------- + * + * --------------------------------------------------*/ +SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists() +{ + delete pCplStt_ExcptLst; + delete pWrdStt_ExcptLst; + delete pAutocorr_List; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::IsFileChanged_Imp() +{ + // nur alle 2 Minuten aufs FileSystem zugreifen um den + // Dateistempel zu ueberpruefen + BOOL bRet = FALSE; + + Time nMinTime( 0, 2 ); + Time nAktTime; + if( aLastCheckTime > nAktTime || // ueberlauf ? + ( nAktTime -= aLastCheckTime ) > nMinTime ) // min Zeit vergangen + { + Date aTstDate; Time aTstTime; + if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile, + &aTstDate, &aTstTime ) && + ( aModifiedDate != aTstDate || aModifiedTime != aTstTime )) + { + bRet = TRUE; + // dann mal schnell alle Listen entfernen! + if( CplSttLstLoad & nFlags && pCplStt_ExcptLst ) + delete pCplStt_ExcptLst, pCplStt_ExcptLst = 0; + if( WrdSttLstLoad & nFlags && pWrdStt_ExcptLst ) + delete pWrdStt_ExcptLst, pWrdStt_ExcptLst = 0; + if( ChgWordLstLoad & nFlags && pAutocorr_List ) + delete pAutocorr_List, pAutocorr_List = 0; + nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad ); + } + aLastCheckTime = Time(); + } + return bRet; +} + +void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp( + SvStringsISortDtor*& rpLst, + const sal_Char* pStrmName, + SotStorageRef& rStg) +{ + if( rpLst ) + rpLst->DeleteAndDestroy( 0, rpLst->Count() ); + else + rpLst = new SvStringsISortDtor( 16, 16 ); + + { + String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 ); + String sTmp( sStrmName ); + + if( rStg.Is() && rStg->IsStream( sStrmName ) ) + { + SvStorageStreamRef xStrm = rStg->OpenSotStream( sTmp, + ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) ); + if( SVSTREAM_OK != xStrm->GetError()) + { + xStrm.Clear(); + rStg.Clear(); + RemoveStream_Imp( sStrmName ); + } + else + { + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = + comphelper::getProcessServiceFactory(); + DBG_ASSERT( xServiceFactory.is(), + "XMLReader::Read: got no service manager" ); + if( !xServiceFactory.is() ) + { + // Throw an exception ? + } + + xml::sax::InputSource aParserInput; + aParserInput.sSystemId = sStrmName; + + xStrm->Seek( 0L ); + xStrm->SetBufferSize( 8 * 1024 ); + aParserInput.aInputStream = new utl::OInputStreamWrapper( *xStrm ); + + // get parser + uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance( + OUString::createFromAscii("com.sun.star.xml.sax.Parser") ); + DBG_ASSERT( xXMLParser.is(), + "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" ); + if( !xXMLParser.is() ) + { + // Maybe throw an exception? + } + + // get filter + // #110680# + // uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( *rpLst ); + uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( xServiceFactory, *rpLst ); + + // connect parser and filter + uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY ); + xParser->setDocumentHandler( xFilter ); + + // parse + try + { + xParser->parseStream( aParserInput ); + } + catch( xml::sax::SAXParseException& ) + { + // re throw ? + } + catch( xml::sax::SAXException& ) + { + // re throw ? + } + catch( io::IOException& ) + { + // re throw ? + } + } + } + + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + } + +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SaveExceptList_Imp( + const SvStringsISortDtor& rLst, + const sal_Char* pStrmName, + SotStorageRef &rStg, + BOOL bConvert ) +{ + if( rStg.Is() ) + { + String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 ); + if( !rLst.Count() ) + { + rStg->Remove( sStrmName ); + rStg->Commit(); + } + else + { + SotStorageStreamRef xStrm = rStg->OpenSotStream( sStrmName, + ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) ); + if( xStrm.Is() ) + { + xStrm->SetSize( 0 ); + xStrm->SetBufferSize( 8192 ); + String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) ); + OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") ); + uno::Any aAny; + aAny <<= aMime; + xStrm->SetProperty( aPropName, aAny ); + + + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = + comphelper::getProcessServiceFactory(); + DBG_ASSERT( xServiceFactory.is(), + "XMLReader::Read: got no service manager" ); + if( !xServiceFactory.is() ) + { + // Throw an exception ? + } + + uno::Reference < XInterface > xWriter (xServiceFactory->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer")))); + DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing"); + uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *xStrm ); + uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY); + xSrc->setOutputStream(xOut); + + uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY); + + // #110680# + // SvXMLExceptionListExport aExp(rLst, sStrmName, xHandler); + SvXMLExceptionListExport aExp( xServiceFactory, rLst, sStrmName, xHandler ); + + aExp.exportDoc( XML_BLOCK_LIST ); + + xStrm->Commit(); + if( xStrm->GetError() == SVSTREAM_OK ) + { + xStrm.Clear(); + if (!bConvert) + { + rStg->Commit(); + if( SVSTREAM_OK != rStg->GetError() ) + { + rStg->Remove( sStrmName ); + rStg->Commit(); + } + } + } + } + } + } +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvxAutocorrWordList* SvxAutoCorrectLanguageLists::LoadAutocorrWordList() +{ + if( pAutocorr_List ) + pAutocorr_List->DeleteAndDestroy( 0, pAutocorr_List->Count() ); + else + pAutocorr_List = new SvxAutocorrWordList( 16, 16 ); + + SvStringsDtor aRemoveArr; + try + { + uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile, embed::ElementModes::READ ); + String aXMLWordListName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 ); + uno::Reference < io::XStream > xStrm = xStg->openStreamElement( aXMLWordListName, embed::ElementModes::READ ); + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = comphelper::getProcessServiceFactory(); + + xml::sax::InputSource aParserInput; + aParserInput.sSystemId = aXMLWordListName; + aParserInput.aInputStream = xStrm->getInputStream(); + + // get parser + uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance( OUString::createFromAscii("com.sun.star.xml.sax.Parser") ); + DBG_ASSERT( xXMLParser.is(), "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" ); + if( xXMLParser.is() ) + { + uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLAutoCorrectImport( xServiceFactory, pAutocorr_List, rAutoCorrect, xStg ); + + // connect parser and filter + uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY ); + xParser->setDocumentHandler( xFilter ); + + // parse + xParser->parseStream( aParserInput ); + } + } + catch ( uno::Exception& ) + { + } + + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + + return pAutocorr_List; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ + +void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList* pList ) +{ + if( pAutocorr_List && pList != pAutocorr_List ) + delete pAutocorr_List; + pAutocorr_List = pList; + if( !pAutocorr_List ) + { + DBG_ASSERT( !this, "keine gueltige Liste" ); + pAutocorr_List = new SvxAutocorrWordList( 16, 16 ); + } + nFlags |= ChgWordLstLoad; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +const SvxAutocorrWordList* SvxAutoCorrectLanguageLists::GetAutocorrWordList() +{ + if( !( ChgWordLstLoad & nFlags ) || IsFileChanged_Imp() ) + SetAutocorrWordList( LoadAutocorrWordList() ); + return pAutocorr_List; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetCplSttExceptList() +{ + if( !( CplSttLstLoad & nFlags ) || IsFileChanged_Imp() ) + SetCplSttExceptList( LoadCplSttExceptList() ); + return pCplStt_ExcptLst; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const String& rNew) +{ + String* pNew = new String( rNew ); + if( rNew.Len() && GetCplSttExceptList()->Insert( pNew ) ) + { + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg ); + + xStg = 0; + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + } + else + delete pNew, pNew = 0; + return 0 != pNew; +} +/* -----------------18.11.98 15:20------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const String& rNew) +{ + String* pNew = new String( rNew ); + SvStringsISortDtor* pExceptList = LoadWrdSttExceptList(); + if( rNew.Len() && pExceptList && pExceptList->Insert( pNew ) ) + { + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg ); + + xStg = 0; + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + } + else + delete pNew, pNew = 0; + return 0 != pNew; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadCplSttExceptList() +{ + SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, TRUE ); + String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) ); + if( xStg.Is() && xStg->IsContained( sTemp ) ) + LoadXMLExceptList_Imp( pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg ); + + return pCplStt_ExcptLst; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SaveCplSttExceptList() +{ + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg ); + + xStg = 0; + + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor* pList ) +{ + if( pCplStt_ExcptLst && pList != pCplStt_ExcptLst ) + delete pCplStt_ExcptLst; + + pCplStt_ExcptLst = pList; + if( !pCplStt_ExcptLst ) + { + DBG_ASSERT( !this, "keine gueltige Liste" ); + pCplStt_ExcptLst = new SvStringsISortDtor( 16, 16 ); + } + nFlags |= CplSttLstLoad; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList() +{ + SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, TRUE ); + String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) ); + if( xStg.Is() && xStg->IsContained( sTemp ) ) + LoadXMLExceptList_Imp( pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg ); + return pWrdStt_ExcptLst; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList() +{ + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg ); + + xStg = 0; + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor* pList ) +{ + if( pWrdStt_ExcptLst && pList != pWrdStt_ExcptLst ) + delete pWrdStt_ExcptLst; + pWrdStt_ExcptLst = pList; + if( !pWrdStt_ExcptLst ) + { + DBG_ASSERT( !this, "keine gueltige Liste" ); + pWrdStt_ExcptLst = new SvStringsISortDtor( 16, 16 ); + } + nFlags |= WrdSttLstLoad; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetWrdSttExceptList() +{ + if( !( WrdSttLstLoad & nFlags ) || IsFileChanged_Imp() ) + SetWrdSttExceptList( LoadWrdSttExceptList() ); + return pWrdStt_ExcptLst; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const String& rName ) +{ + if( sShareAutoCorrFile != sUserAutoCorrFile ) + { + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + if( xStg.Is() && SVSTREAM_OK == xStg->GetError() && + xStg->IsStream( rName ) ) + { + xStg->Remove( rName ); + xStg->Commit(); + + xStg = 0; + } + } +} + +void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl() +{ + // The conversion needs to happen if the file is already in the user + // directory and is in the old format. Additionally it needs to + // happen when the file is being copied from share to user. + + sal_Bool bError = sal_False, bConvert = sal_False, bCopy = sal_False; + INetURLObject aDest; + INetURLObject aSource; + +// String sDestPath = sUserAutoCorrFile.Copy ( 0, sUserAutoCorrFile.Len()-3); +// sDestPath.AppendAscii ("bak"); + + + if (sUserAutoCorrFile != sShareAutoCorrFile ) + { + aSource = INetURLObject ( sShareAutoCorrFile ); //aSource.setFSysPath ( sShareAutoCorrFile, INetURLObject::FSYS_DETECT ); + aDest = INetURLObject ( sUserAutoCorrFile ); + if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile ) ) + { + aDest.SetExtension ( String::CreateFromAscii ( "bak" ) ); + bConvert = sal_True; + } + bCopy = sal_True; + } + else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile ) ) + { + aSource = INetURLObject ( sUserAutoCorrFile ); + aDest = INetURLObject ( sUserAutoCorrFile ); + aDest.SetExtension ( String::CreateFromAscii ( "bak" ) ); + bCopy = bConvert = sal_True; + } + if (bCopy) + { + try + { + String sMain(aDest.GetMainURL( INetURLObject::DECODE_TO_IURI )); + sal_Unicode cSlash = '/'; + xub_StrLen nSlashPos = sMain.SearchBackward(cSlash); + sMain.Erase(nSlashPos); + ::ucbhelper::Content aNewContent( sMain, uno::Reference< XCommandEnvironment > ()); + Any aAny; + TransferInfo aInfo; + aInfo.NameClash = NameClash::OVERWRITE; + aInfo.NewTitle = aDest.GetName(); + aInfo.SourceURL = aSource.GetMainURL( INetURLObject::DECODE_TO_IURI ); + aInfo.MoveData = FALSE; + aAny <<= aInfo; + aNewContent.executeCommand( OUString ( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ), aAny); + } + catch (...) + { + bError = sal_True; + } + } + if (bConvert && !bError) + { + SotStorageRef xSrcStg = new SotStorage( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), STREAM_READ, TRUE ); + SotStorageRef xDstStg = new SotStorage( sUserAutoCorrFile, STREAM_WRITE, TRUE ); + + if( xSrcStg.Is() && xDstStg.Is() ) + { + String sWord ( RTL_CONSTASCII_USTRINGPARAM ( pImplWrdStt_ExcptLstStr ) ); + String sSentence ( RTL_CONSTASCII_USTRINGPARAM ( pImplCplStt_ExcptLstStr ) ); + String sXMLWord ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) ); + String sXMLSentence ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) ); + SvStringsISortDtor *pTmpWordList = NULL; + + if (xSrcStg->IsContained( sXMLWord ) ) + LoadXMLExceptList_Imp( pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xSrcStg ); + + if (pTmpWordList) + { + SaveExceptList_Imp( *pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xDstStg, TRUE ); + pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() ); + pTmpWordList = NULL; + } + + + if (xSrcStg->IsContained( sXMLSentence ) ) + LoadXMLExceptList_Imp( pTmpWordList, pXMLImplCplStt_ExcptLstStr, xSrcStg ); + + if (pTmpWordList) + { + SaveExceptList_Imp( *pTmpWordList, pXMLImplCplStt_ExcptLstStr, xDstStg, TRUE ); + pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() ); + } + + GetAutocorrWordList(); + MakeBlocklist_Imp( *xDstStg ); + // xDstStg is committed in MakeBlocklist_Imp + /*xSrcStg->CopyTo( &xDstStg );*/ + sShareAutoCorrFile = sUserAutoCorrFile; + xDstStg = 0; + try + { + ::ucbhelper::Content aContent ( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), uno::Reference < XCommandEnvironment > ()); + aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "delete" ) ), makeAny ( sal_Bool (sal_True ) ) ); + } + catch (...) + { + } + } + } + else if( bCopy && !bError ) + sShareAutoCorrFile = sUserAutoCorrFile; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage& rStg ) +{ + String sStrmName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 ); + BOOL bRet = TRUE, bRemove = !pAutocorr_List || !pAutocorr_List->Count(); + if( !bRemove ) + { + /* + if ( rStg.IsContained( sStrmName) ) + { + rStg.Remove ( sStrmName ); + rStg.Commit(); + } + */ + SvStorageStreamRef refList = rStg.OpenSotStream( sStrmName, + ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) ); + if( refList.Is() ) + { + refList->SetSize( 0 ); + refList->SetBufferSize( 8192 ); + String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) ); + OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") ); + uno::Any aAny; + aAny <<= aMime; + refList->SetProperty( aPropName, aAny ); + + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = + comphelper::getProcessServiceFactory(); + DBG_ASSERT( xServiceFactory.is(), + "XMLReader::Read: got no service manager" ); + if( !xServiceFactory.is() ) + { + // Throw an exception ? + } + + uno::Reference < XInterface > xWriter (xServiceFactory->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer")))); + DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing"); + uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *refList ); + uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY); + xSrc->setOutputStream(xOut); + + uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY); + + // #110680# + // SvXMLAutoCorrectExport aExp(pAutocorr_List, sStrmName, xHandler); + SvXMLAutoCorrectExport aExp( xServiceFactory, pAutocorr_List, sStrmName, xHandler ); + + aExp.exportDoc( XML_BLOCK_LIST ); + + refList->Commit(); + bRet = SVSTREAM_OK == refList->GetError(); + if( bRet ) + { + refList.Clear(); + rStg.Commit(); + if( SVSTREAM_OK != rStg.GetError() ) + { + bRemove = TRUE; + bRet = FALSE; + } + } + + /* + refList->SetSize( 0 ); + refList->SetBufferSize( 8192 ); + rtl_TextEncoding eEncoding = gsl_getSystemTextEncoding(); + + String aDummy; // Erkennungszeichen fuer neue Streams + refList->WriteByteString( aDummy, RTL_TEXTENCODING_MS_1252 ) + << (BYTE) 4 // Laenge des Headers (ohne den Leerstring) + << (USHORT)WORDLIST_VERSION_358 // Version des Streams + << (BYTE)eEncoding; // der Zeichensatz + + for( USHORT i = 0; i < pAutocorr_List->Count() && + SVSTREAM_OK == refList->GetError(); ++i ) + { + SvxAutocorrWord* p = pAutocorr_List->GetObject( i ); + refList->WriteByteString( p->GetShort(), eEncoding ). + WriteByteString( p->IsTextOnly() + ? p->GetLong() + : p->GetShort(), eEncoding ); + } + refList->Commit(); + bRet = SVSTREAM_OK == refList->GetError(); + if( bRet ) + { + refList.Clear(); + rStg.Commit(); + if( SVSTREAM_OK != rStg.GetError() ) + { + bRemove = TRUE; + bRet = FALSE; + } + } + */ + } + else + bRet = FALSE; + } + + if( bRemove ) + { + rStg.Remove( sStrmName ); + rStg.Commit(); + } + + return bRet; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::PutText( const String& rShort, + const String& rLong ) +{ + // erstmal akt. Liste besorgen! + GetAutocorrWordList(); + + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + BOOL bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError(); + +/* if( bRet ) + { + // PutText( *xStg, rShort ); + } +*/ + // die Wortliste aktualisieren + if( bRet ) + { + USHORT nPos; + SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, rLong, TRUE ); + if( pAutocorr_List->Seek_Entry( pNew, &nPos ) ) + { + if( !(*pAutocorr_List)[ nPos ]->IsTextOnly() ) + { + // dann ist der Storage noch zu entfernen + String sStgNm( rShort ); + if (xStg->IsOLEStorage()) + EncryptBlockName_Imp( sStgNm ); + else + GeneratePackageName ( rShort, sStgNm); + + if( xStg->IsContained( sStgNm ) ) + xStg->Remove( sStgNm ); + } + pAutocorr_List->DeleteAndDestroy( nPos ); + } + + if( pAutocorr_List->Insert( pNew ) ) + { + bRet = MakeBlocklist_Imp( *xStg ); + xStg = 0; + } + else + { + delete pNew; + bRet = FALSE; + } + } + return bRet; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ + // - Text mit Attributierung (kann nur der SWG - SWG-Format!) +BOOL SvxAutoCorrectLanguageLists::PutText( const String& rShort, + SfxObjectShell& rShell ) +{ + // erstmal akt. Liste besorgen! + GetAutocorrWordList(); + + MakeUserStorage_Impl(); + + BOOL bRet = FALSE; + String sLong; + try + { + uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile, embed::ElementModes::READWRITE ); +// String aName( rShort ); +// EncryptBlockName_Imp( aName ); +// bRet = PutText( *xStg, aName, rShell, sLong ); + bRet = rAutoCorrect.PutText( xStg, sUserAutoCorrFile, rShort, rShell, sLong ); + xStg = 0; + + // die Wortliste aktualisieren + if( bRet ) + { + SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, sLong, FALSE ); + if( pAutocorr_List->Insert( pNew ) ) + { + SotStorageRef xStor = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + MakeBlocklist_Imp( *xStor ); + } + else + delete pNew; + } + } + catch ( uno::Exception& ) + { + } + + return bRet; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ + // - loesche einen Eintrag +BOOL SvxAutoCorrectLanguageLists::DeleteText( const String& rShort ) +{ + // erstmal akt. Liste besorgen! + GetAutocorrWordList(); + + MakeUserStorage_Impl(); + + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + BOOL bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError(); + if( bRet ) + { + USHORT nPos; + SvxAutocorrWord aTmp( rShort, rShort ); + if( pAutocorr_List->Seek_Entry( &aTmp, &nPos ) ) + { + SvxAutocorrWord* pFnd = (*pAutocorr_List)[ nPos ]; + if( !pFnd->IsTextOnly() ) + { + String aName( rShort ); + if (xStg->IsOLEStorage()) + EncryptBlockName_Imp( aName ); + else + GeneratePackageName ( rShort, aName ); + if( xStg->IsContained( aName ) ) + { + xStg->Remove( aName ); + bRet = xStg->Commit(); + } + + } + // die Wortliste aktualisieren + pAutocorr_List->DeleteAndDestroy( nPos ); + MakeBlocklist_Imp( *xStg ); + xStg = 0; + } + else + bRet = FALSE; + } + return bRet; +} diff --git a/editeng/source/misc/swafopt.cxx b/editeng/source/misc/swafopt.cxx new file mode 100644 index 000000000000..f693ce0270f8 --- /dev/null +++ b/editeng/source/misc/swafopt.cxx @@ -0,0 +1,158 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <vcl/keycodes.hxx> +#include <tools/string.hxx> + +#include <editeng/swafopt.hxx> + +/*------------------------------------------------------------------------ + Beschreibung: +------------------------------------------------------------------------*/ + +SvxSwAutoFmtFlags::SvxSwAutoFmtFlags() + : aBulletFont( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "StarSymbol" )), + Size( 0, 14 ) ) +{ + bAutoCorrect = + bCptlSttSntnc = + bCptlSttWrd = + bChkFontAttr = + bChgUserColl = + bChgEnumNum = + bAddNonBrkSpace = + bChgOrdinalNumber = + bChgToEnEmDash = + bChgWeightUnderl = + bSetINetAttr = + bAFmtDelSpacesAtSttEnd = + bAFmtDelSpacesBetweenLines = + bAFmtByInpDelSpacesAtSttEnd = + bAFmtByInpDelSpacesBetweenLines = + bDummy = TRUE; + + bReplaceStyles = + bDelEmptyNode = + bWithRedlining = + bAutoCmpltEndless = + bAutoCmpltAppendBlanc = + bAutoCmpltShowAsTip = FALSE; + + bSetBorder = + bCreateTable = + bSetNumRule = + bAFmtByInput = + bRightMargin = + bAutoCompleteWords = + bAutoCmpltCollectWords = + bAutoCmpltKeepList = TRUE; + + bDummy6 = bDummy7 = bDummy8 = + FALSE; + + nRightMargin = 50; // dflt. 50 % + nAutoCmpltExpandKey = KEY_RETURN; + + aBulletFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); + aBulletFont.SetFamily( FAMILY_DONTKNOW ); + aBulletFont.SetPitch( PITCH_DONTKNOW ); + aBulletFont.SetWeight( WEIGHT_DONTKNOW ); + aBulletFont.SetTransparent( TRUE ); + + cBullet = 0x2022; + cByInputBullet = cBullet; + aByInputBulletFont = aBulletFont; + + nAutoCmpltWordLen = 10; + nAutoCmpltListLen = 500; + pAutoCmpltList = 0; + pSmartTagMgr = 0; +} + + +SvxSwAutoFmtFlags& SvxSwAutoFmtFlags::operator=( const SvxSwAutoFmtFlags& rAFFlags ) +{ + bAutoCorrect = rAFFlags.bAutoCorrect; + bCptlSttSntnc = rAFFlags.bCptlSttSntnc; + bCptlSttWrd = rAFFlags.bCptlSttWrd; + bChkFontAttr = rAFFlags.bChkFontAttr; + + bChgUserColl = rAFFlags.bChgUserColl; + bChgEnumNum = rAFFlags.bChgEnumNum; + bDelEmptyNode = rAFFlags.bDelEmptyNode; + bSetNumRule = rAFFlags.bSetNumRule; + bAFmtByInput = rAFFlags.bAFmtByInput; + + bAddNonBrkSpace = rAFFlags.bAddNonBrkSpace; + bChgOrdinalNumber = rAFFlags.bChgOrdinalNumber; + bChgToEnEmDash = rAFFlags.bChgToEnEmDash; + bChgWeightUnderl = rAFFlags.bChgWeightUnderl; + bSetINetAttr = rAFFlags.bSetINetAttr; + bSetBorder = rAFFlags.bSetBorder; + bCreateTable = rAFFlags.bCreateTable; + bReplaceStyles = rAFFlags.bReplaceStyles; + bAFmtDelSpacesAtSttEnd = rAFFlags.bAFmtDelSpacesAtSttEnd; + bAFmtDelSpacesBetweenLines = rAFFlags.bAFmtDelSpacesBetweenLines; + bAFmtByInpDelSpacesAtSttEnd = rAFFlags.bAFmtByInpDelSpacesAtSttEnd; + bAFmtByInpDelSpacesBetweenLines = rAFFlags.bAFmtByInpDelSpacesBetweenLines; + + bDummy = rAFFlags.bDummy; + + bDummy6 = rAFFlags.bDummy6; + bDummy7 = rAFFlags.bDummy7; + bDummy8 = rAFFlags.bDummy8; + + bWithRedlining = rAFFlags.bWithRedlining; + + bRightMargin = rAFFlags.bRightMargin; + nRightMargin = rAFFlags.nRightMargin; + + cBullet = rAFFlags.cBullet; + aBulletFont = rAFFlags.aBulletFont; + + cByInputBullet = rAFFlags.cByInputBullet; + aByInputBulletFont = rAFFlags.aByInputBulletFont; + + bAutoCompleteWords = rAFFlags.bAutoCompleteWords; + bAutoCmpltCollectWords = rAFFlags.bAutoCmpltCollectWords; + bAutoCmpltKeepList = rAFFlags.bAutoCmpltKeepList; + bAutoCmpltEndless = rAFFlags.bAutoCmpltEndless; + bAutoCmpltAppendBlanc = rAFFlags.bAutoCmpltAppendBlanc; + bAutoCmpltShowAsTip = rAFFlags.bAutoCmpltShowAsTip; + pAutoCmpltList = rAFFlags.pAutoCmpltList; + pSmartTagMgr = rAFFlags.pSmartTagMgr; + nAutoCmpltExpandKey = rAFFlags.nAutoCmpltExpandKey; + + nAutoCmpltWordLen = rAFFlags.nAutoCmpltWordLen; + nAutoCmpltListLen = rAFFlags.nAutoCmpltListLen; + + return *this; +} + diff --git a/editeng/source/misc/txtrange.cxx b/editeng/source/misc/txtrange.cxx new file mode 100644 index 000000000000..2bc219e9b69c --- /dev/null +++ b/editeng/source/misc/txtrange.cxx @@ -0,0 +1,719 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/txtrange.hxx> +#include <math.h> +#include <tools/poly.hxx> +#include <tools/debug.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +/************************************************************************* +|* +|* TextRanger::TextRanger() +|* +|* Beschreibung +|* Ersterstellung 20.01.97 +|* Letzte Aenderung 20.01.97 AMA +|* +*************************************************************************/ + +#ifdef WIN +#pragma optimize ( "", off ) +#endif + +TextRanger::TextRanger( const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DPolyPolygon* pLinePolyPolygon, + USHORT nCacheSz, USHORT nLft, USHORT nRght, BOOL bSimpl, BOOL bInnr, + BOOL bVert ) : + pBound( NULL ), + nCacheSize( nCacheSz ), + nCacheIdx( 0 ), + nRight( nRght ), + nLeft( nLft ), + nUpper( 0 ), + nLower( 0 ), + nPointCount( 0 ), + bSimple( bSimpl ), + bInner( bInnr ), + bVertical( bVert ) +{ +#ifdef DBG_UTIL + bFlag3 = bFlag4 = bFlag5 = bFlag6 = bFlag7 = FALSE; +#endif + pRangeArr = new Range[ nCacheSize ]; + pCache = new SvLongsPtr[ nCacheSize ]; + memset( pRangeArr, 0, nCacheSize * sizeof( Range ) ); + memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) ); + sal_uInt32 nCount(rPolyPolygon.count()); + mpPolyPolygon = new PolyPolygon( (sal_uInt16)nCount ); + + for(sal_uInt32 i(0L); i < nCount; i++) + { + const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(i).getDefaultAdaptiveSubdivision()); + nPointCount += aCandidate.count(); + mpPolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i ); + } + + if( pLinePolyPolygon ) + { + nCount = pLinePolyPolygon->count(); + mpLinePolyPolygon = new PolyPolygon(); + + for(sal_uInt32 i(0L); i < nCount; i++) + { + const basegfx::B2DPolygon aCandidate(pLinePolyPolygon->getB2DPolygon(i).getDefaultAdaptiveSubdivision()); + nPointCount += aCandidate.count(); + mpLinePolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i ); + } + } + else + mpLinePolyPolygon = NULL; +} + +#ifdef WIN +#pragma optimize ( "", on ) +#endif + +/************************************************************************* +|* +|* TextRanger::~TextRanger() +|* +|* Beschreibung +|* Ersterstellung 20.01.97 +|* Letzte Aenderung 20.01.97 AMA +|* +*************************************************************************/ + +TextRanger::~TextRanger() +{ + for( USHORT i = 0; i < nCacheSize; ++i ) + delete pCache[i]; + delete[] pCache; + delete[] pRangeArr; + delete mpPolyPolygon; + delete mpLinePolyPolygon; +} + +/*-----------------17.11.00 09:49------------------- + * TextRanger::SetVertical(..) + * If there's is a change in the writing direction, + * the cache has to be cleared. + * --------------------------------------------------*/ + +void TextRanger::SetVertical( BOOL bNew ) +{ + if( IsVertical() != bNew ) + { + bVertical = bNew; + for( USHORT i = 0; i < nCacheSize; ++i ) + delete pCache[i]; + memset( pRangeArr, 0, nCacheSize * sizeof( Range ) ); + memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) ); + } +} + +/************************************************************************* +|* +|* SvxBoundArgs +|* +|* Beschreibung +|* Ersterstellung 20.01.97 +|* Letzte Aenderung 20.01.97 AMA +|* +*************************************************************************/ + +class SvxBoundArgs +{ + SvBools aBoolArr; + SvLongs *pLongArr; + TextRanger *pTextRanger; + long nMin; + long nMax; + long nTop; + long nBottom; + long nUpDiff; + long nLowDiff; + long nUpper; + long nLower; + long nStart; + long nEnd; + USHORT nCut; + USHORT nLast; + USHORT nNext; + BYTE nAct; + BYTE nFirst; + BOOL bClosed : 1; + BOOL bInner : 1; + BOOL bMultiple : 1; + BOOL bConcat : 1; + BOOL bRotate : 1; + void NoteRange( BOOL bToggle ); + long Cut( long nY, const Point& rPt1, const Point& rPt2 ); + void Add(); + void _NoteFarPoint( long nPx, long nPyDiff, long nDiff ); + void NoteFarPoint( long nPx, long nPyDiff, long nDiff ) + { if( nDiff ) _NoteFarPoint( nPx, nPyDiff, nDiff ); } + long CalcMax( const Point& rPt1, const Point& rPt2, long nRange, long nFar ); + void CheckCut( const Point& rLst, const Point& rNxt ); + inline long A( const Point& rP ) const { return bRotate ? rP.Y() : rP.X(); } + inline long B( const Point& rP ) const { return bRotate ? rP.X() : rP.Y(); } +public: + SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong, const Range& rRange ); + void NotePoint( const long nA ) { NoteMargin( nA - nStart, nA + nEnd ); } + void NoteMargin( const long nL, const long nR ) + { if( nMin > nL ) nMin = nL; if( nMax < nR ) nMax = nR; } + USHORT Area( const Point& rPt ); + void NoteUpLow( long nA, const BYTE nArea ); + void Calc( const PolyPolygon& rPoly ); + void Concat( const PolyPolygon* pPoly ); + // inlines + void NoteLast() { if( bMultiple ) NoteRange( nAct == nFirst ); } + void SetClosed( const BOOL bNew ){ bClosed = bNew; } + BOOL IsClosed() const { return bClosed; } + void SetConcat( const BOOL bNew ){ bConcat = bNew; } + BOOL IsConcat() const { return bConcat; } + BYTE GetAct() const { return nAct; } +}; + +SvxBoundArgs::SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong, + const Range& rRange ) + : aBoolArr( 4, 4 ), pLongArr( pLong ), pTextRanger( pRanger ), + nTop( rRange.Min() ), nBottom( rRange.Max() ), + bInner( pRanger->IsInner() ), bMultiple( bInner || !pRanger->IsSimple() ), + bConcat( FALSE ), bRotate( pRanger->IsVertical() ) +{ + if( bRotate ) + { + nStart = pRanger->GetUpper(); + nEnd = pRanger->GetLower(); + nLowDiff = pRanger->GetLeft(); + nUpDiff = pRanger->GetRight(); + } + else + { + nStart = pRanger->GetLeft(); + nEnd = pRanger->GetRight(); + nLowDiff = pRanger->GetUpper(); + nUpDiff = pRanger->GetLower(); + } + nUpper = nTop - nUpDiff; + nLower = nBottom + nLowDiff; + pLongArr->Remove( 0, pLongArr->Count() ); +} + +long SvxBoundArgs::CalcMax( const Point& rPt1, const Point& rPt2, + long nRange, long nFarRange ) +{ + double nDa = Cut( nRange, rPt1, rPt2 ) - Cut( nFarRange, rPt1, rPt2 ); + double nB; + if( nDa < 0 ) + { + nDa = -nDa; + nB = nEnd; + } + else + nB = nStart; + nB *= nB; + nB += nDa * nDa; + nB = nRange + nDa * ( nFarRange - nRange ) / sqrt( nB ); + + BOOL bNote; + if( nB < B(rPt2) ) + bNote = nB > B(rPt1); + else + bNote = nB < B(rPt1); + if( bNote ) + return( long( nB ) ); + return 0; +} + +void SvxBoundArgs::CheckCut( const Point& rLst, const Point& rNxt ) +{ + if( nCut & 1 ) + NotePoint( Cut( nBottom, rLst, rNxt ) ); + if( nCut & 2 ) + NotePoint( Cut( nTop, rLst, rNxt ) ); + if( rLst.X() != rNxt.X() && rLst.Y() != rNxt.Y() ) + { + long nYps; + if( nLowDiff && ( ( nCut & 1 ) || nLast == 1 || nNext == 1 ) ) + { + nYps = CalcMax( rLst, rNxt, nBottom, nLower ); + if( nYps ) + _NoteFarPoint( Cut( nYps, rLst, rNxt ), nLower-nYps, nLowDiff ); + } + if( nUpDiff && ( ( nCut & 2 ) || nLast == 2 || nNext == 2 ) ) + { + nYps = CalcMax( rLst, rNxt, nTop, nUpper ); + if( nYps ) + _NoteFarPoint( Cut( nYps, rLst, rNxt ), nYps-nUpper, nUpDiff ); + } + } +} + +void SvxBoundArgs::_NoteFarPoint( long nPa, long nPbDiff, long nDiff ) +{ + long nTmpA; + double nQuot = 2 * nDiff - nPbDiff; + nQuot *= nPbDiff; + nQuot = sqrt( nQuot ); + nQuot /= nDiff; + nTmpA = nPa - long( nStart * nQuot ); + nPbDiff = nPa + long( nEnd * nQuot ); + NoteMargin( nTmpA, nPbDiff ); +} + +void SvxBoundArgs::NoteRange( BOOL bToggle ) +{ + DBG_ASSERT( nMax >= nMin || bInner, "NoteRange: Min > Max?"); + if( nMax < nMin ) + return; + if( !bClosed ) + bToggle = FALSE; + USHORT nIdx = 0; + USHORT nCount = pLongArr->Count(); + DBG_ASSERT( nCount == 2 * aBoolArr.Count(), "NoteRange: Incompatible Sizes" ); + while( nIdx < nCount && (*pLongArr)[ nIdx ] < nMin ) + ++nIdx; + BOOL bOdd = nIdx % 2 ? TRUE : FALSE; + // Kein Ueberlappung mit vorhandenen Intervallen? + if( nIdx == nCount || ( !bOdd && nMax < (*pLongArr)[ nIdx ] ) ) + { // Dann wird ein neues eingefuegt ... + pLongArr->Insert( nMin, nIdx ); + pLongArr->Insert( nMax, nIdx + 1 ); + aBoolArr.Insert( bToggle, nIdx / 2 ); + } + else + { // ein vorhandes Intervall erweitern ... + USHORT nMaxIdx = nIdx; + // Wenn wir auf einer linken Intervallgrenze gelandet sind, muss diese + // auf nMin gesenkt werden. + if( bOdd ) + --nIdx; + else + (*pLongArr)[ nIdx ] = nMin; + while( nMaxIdx < nCount && (*pLongArr)[ nMaxIdx ] < nMax ) + ++nMaxIdx; + DBG_ASSERT( nMaxIdx > nIdx || nMin == nMax, "NoteRange: Funny Situation." ); + if( nMaxIdx ) + --nMaxIdx; + if( nMaxIdx < nIdx ) + nMaxIdx = nIdx; + // Wenn wir auf einer rechten Intervallgrenze landen, muss diese + // auf nMax angehoben werden. + if( nMaxIdx % 2 ) + (*pLongArr)[ nMaxIdx-- ] = nMax; + // Jetzt werden eventuell noch Intervalle verschmolzen + USHORT nDiff = nMaxIdx - nIdx; + nMaxIdx = nIdx / 2; // Ab hier ist nMaxIdx der Index im BoolArray. + if( nDiff ) + { + (*pLongArr).Remove( nIdx + 1, nDiff ); + nDiff /= 2; + USHORT nStop = nMaxIdx + nDiff; + for( USHORT i = nMaxIdx; i < nStop; ++i ) + bToggle ^= aBoolArr[ i ]; + aBoolArr.Remove( nMaxIdx, nDiff ); + } + DBG_ASSERT( nMaxIdx < aBoolArr.Count(), "NoteRange: Too much deleted" ); + aBoolArr[ nMaxIdx ] ^= bToggle; + } +} + +void SvxBoundArgs::Calc( const PolyPolygon& rPoly ) +{ + USHORT nCount; + nAct = 0; + for( USHORT i = 0; i < rPoly.Count(); ++i ) + { + const Polygon& rPol = rPoly[ i ]; + nCount = rPol.GetSize(); + if( nCount ) + { + const Point& rNull = rPol[ 0 ]; + SetClosed( IsConcat() || ( rNull == rPol[ nCount - 1 ] ) ); + nLast = Area( rNull ); + if( nLast & 12 ) + { + nFirst = 3; + if( bMultiple ) + nAct = 0; + } + else + { + // Der erste Punkt des Polygons liegt innerhalb der Zeile. + if( nLast ) + { + if( bMultiple || !nAct ) + { + nMin = USHRT_MAX; + nMax = 0; + } + if( nLast & 1 ) + NoteFarPoint( A(rNull), nLower - B(rNull), nLowDiff ); + else + NoteFarPoint( A(rNull), B(rNull) - nUpper, nUpDiff ); + } + else + { + if( bMultiple || !nAct ) + { + nMin = A(rNull); + nMax = nMin + nEnd; + nMin -= nStart; + } + else + NotePoint( A(rNull) ); + } + nFirst = 0; // In welcher Richtung wird die Zeile verlassen? + nAct = 3; // Wir sind z.Z. innerhalb der Zeile. + } + if( nCount > 1 ) + { + USHORT nIdx = 1; + while( TRUE ) + { + const Point& rLast = rPol[ nIdx - 1 ]; + if( nIdx == nCount ) + nIdx = 0; + const Point& rNext = rPol[ nIdx ]; + nNext = Area( rNext ); + nCut = nNext ^ nLast; + USHORT nOldAct = nAct; + if( nAct ) + CheckCut( rLast, rNext ); + if( nCut & 4 ) + { + NoteUpLow( Cut( nLower, rLast, rNext ), 2 ); + if( nAct && nAct != nOldAct ) + { + nOldAct = nAct; + CheckCut( rLast, rNext ); + } + } + if( nCut & 8 ) + { + NoteUpLow( Cut( nUpper, rLast, rNext ), 1 ); + if( nAct && nAct != nOldAct ) + CheckCut( rLast, rNext ); + } + if( !nIdx ) + { + if( !( nNext & 12 ) ) + NoteLast(); + break; + } + if( !( nNext & 12 ) ) + { + if( !nNext ) + NotePoint( A(rNext) ); + else if( nNext & 1 ) + NoteFarPoint( A(rNext), nLower-B(rNext), nLowDiff ); + else + NoteFarPoint( A(rNext), B(rNext)-nUpper, nUpDiff ); + } + nLast = nNext; + if( ++nIdx == nCount && !IsClosed() ) + { + if( !( nNext & 12 ) ) + NoteLast(); + break; + } + } + } + if( bMultiple && IsConcat() ) + { + Add(); + nAct = 0; + } + } + } + if( !bMultiple ) + { + DBG_ASSERT( pLongArr->Count() == 0, "I said: Simple!" ); + if( nAct ) + { + if( bInner ) + { + long nTmpMin, nTmpMax; + { + nTmpMin = nMin + 2 * nStart; + nTmpMax = nMax - 2 * nEnd; + if( nTmpMin <= nTmpMax ) + { + pLongArr->Insert( nTmpMin, 0 ); + pLongArr->Insert( nTmpMax, 1 ); + } + } + } + else + { + pLongArr->Insert( nMin, 0 ); + pLongArr->Insert( nMax, 1 ); + } + } + } + else if( !IsConcat() ) + Add(); +} + +void SvxBoundArgs::Add() +{ + USHORT nLongIdx = 1; + USHORT nCount = aBoolArr.Count(); + if( nCount && ( !bInner || !pTextRanger->IsSimple() ) ) + { + BOOL bDelete = aBoolArr[ 0 ]; + if( bInner ) + bDelete = !bDelete; + for( USHORT nBoolIdx = 1; nBoolIdx < nCount; ++nBoolIdx ) + { + if( bDelete ) + { + USHORT next = 2; + while( nBoolIdx < nCount && !aBoolArr[ nBoolIdx++ ] && + (!bInner || nBoolIdx < nCount ) ) + next += 2; + pLongArr->Remove( nLongIdx, next ); + next /= 2; + nBoolIdx = nBoolIdx - next; + nCount = nCount - next; + aBoolArr.Remove( nBoolIdx, next ); + if( nBoolIdx ) + aBoolArr[ nBoolIdx - 1 ] = FALSE; +#if OSL_DEBUG_LEVEL > 1 + else + ++next; +#endif + } + bDelete = nBoolIdx < nCount && aBoolArr[ nBoolIdx ]; + nLongIdx += 2; + DBG_ASSERT( nLongIdx == 2*nBoolIdx+1, "BoundArgs: Array-Idx Confusion" ); + DBG_ASSERT( aBoolArr.Count()*2 == pLongArr->Count(), + "BoundArgs: Array-Count: Confusion" ); + } + } + if( 0 != ( nCount = pLongArr->Count() ) ) + { + if( bInner ) + { + pLongArr->Remove( 0, 1 ); + pLongArr->Remove( pLongArr->Count() - 1, 1 ); + + // Hier wird die Zeile beim "einfachen" Konturumfluss im Innern + // in ein grosses Rechteck zusammengefasst. + // Zur Zeit (April 1999) wertet die EditEngine nur das erste Rechteck + // aus, falls sie eines Tages in der Lage ist, eine Zeile in mehreren + // Teilen auszugeben, kann es sinnvoll sein, die folgenden Zeilen + // zu loeschen. + if( pTextRanger->IsSimple() && pLongArr->Count() > 2 ) + pLongArr->Remove( 1, pLongArr->Count() - 2 ); + + } + } +} + +void SvxBoundArgs::Concat( const PolyPolygon* pPoly ) +{ + SetConcat( TRUE ); + DBG_ASSERT( pPoly, "Nothing to do?" ); + SvLongs *pOld = pLongArr; + pLongArr = new SvLongs( 2, 8 ); + aBoolArr.Remove( 0, aBoolArr.Count() ); + bInner = FALSE; + Calc( *pPoly ); + USHORT nCount = pLongArr->Count(); + USHORT nIdx = 0; + USHORT i = 0; + BOOL bSubtract = pTextRanger->IsInner(); + while( i < nCount ) + { + USHORT nOldCount = pOld->Count(); + if( nIdx == nOldCount ) + { // Am Ende des alten Arrays angelangt... + if( !bSubtract ) + pOld->Insert( pLongArr, nIdx, i, USHRT_MAX ); + break; + } + long nLeft = (*pLongArr)[ i++ ]; + long nRight = (*pLongArr)[ i++ ]; + USHORT nLeftPos = nIdx + 1; + while( nLeftPos < nOldCount && nLeft > (*pOld)[ nLeftPos ] ) + nLeftPos += 2; + if( nLeftPos >= nOldCount ) + { // Das aktuelle Intervall gehoert ans Ende des alten Arrays... + if( !bSubtract ) + pOld->Insert( pLongArr, nOldCount, i - 2, USHRT_MAX ); + break; + } + USHORT nRightPos = nLeftPos - 1; + while( nRightPos < nOldCount && nRight >= (*pOld)[ nRightPos ] ) + nRightPos += 2; + if( nRightPos < nLeftPos ) + { // Das aktuelle Intervall gehoert zwischen zwei alte Intervalle + if( !bSubtract ) + pOld->Insert( pLongArr, nRightPos, i - 2, i ); + nIdx = nRightPos + 2; + } + else if( bSubtract ) // Subtrahieren ggf. Trennen + { + long nOld; + if( nLeft > ( nOld = (*pOld)[ nLeftPos - 1 ] ) ) + { // Jetzt spalten wir den linken Teil ab... + if( nLeft - 1 > nOld ) + { + pOld->Insert( nOld, nLeftPos - 1 ); + pOld->Insert( nLeft - 1, nLeftPos ); + nLeftPos += 2; + nRightPos += 2; + } + } + if( nRightPos - nLeftPos > 1 ) + pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 ); + if( ++nRight >= ( nOld = (*pOld)[ nLeftPos ] ) ) + pOld->Remove( nLeftPos - 1, 2 ); + else + (*pOld)[ nLeftPos - 1 ] = nRight; + } + else // Verschmelzen + { + if( nLeft < (*pOld)[ nLeftPos - 1 ] ) + (*pOld)[ nLeftPos - 1 ] = nLeft; + if( nRight > (*pOld)[ nRightPos - 1 ] ) + (*pOld)[ nRightPos - 1 ] = nRight; + if( nRightPos - nLeftPos > 1 ) + pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 ); + + } + nIdx = nLeftPos - 1; + } + delete pLongArr; +} + +/************************************************************************* + * SvxBoundArgs::Area ermittelt den Bereich, in dem sich der Punkt befindet + * 0 = innerhalb der Zeile + * 1 = unterhalb, aber innerhalb der oberen Randes + * 2 = oberhalb, aber innerhalb der unteren Randes + * 5 = unterhalb des oberen Randes + *10 = oberhalb des unteren Randes + *************************************************************************/ + +USHORT SvxBoundArgs::Area( const Point& rPt ) +{ + long nB = B( rPt ); + if( nB >= nBottom ) + { + if( nB >= nLower ) + return 5; + return 1; + } + if( nB <= nTop ) + { + if( nB <= nUpper ) + return 10; + return 2; + } + return 0; +} + +/************************************************************************* + * lcl_Cut berechnet die X-Koordinate der Strecke (Pt1-Pt2) auf der + * Y-Koordinate nY. + * Vorausgesetzt wird, dass einer der Punkte oberhalb und der andere + * unterhalb der Y-Koordinate liegt. + *************************************************************************/ + +long SvxBoundArgs::Cut( long nB, const Point& rPt1, const Point& rPt2 ) +{ + if( pTextRanger->IsVertical() ) + { + double nQuot = nB - rPt1.X(); + nQuot /= ( rPt2.X() - rPt1.X() ); + nQuot *= ( rPt2.Y() - rPt1.Y() ); + return long( rPt1.Y() + nQuot ); + } + double nQuot = nB - rPt1.Y(); + nQuot /= ( rPt2.Y() - rPt1.Y() ); + nQuot *= ( rPt2.X() - rPt1.X() ); + return long( rPt1.X() + nQuot ); +} + +void SvxBoundArgs::NoteUpLow( long nA, const BYTE nArea ) +{ + if( nAct ) + { + NoteMargin( nA, nA ); + if( bMultiple ) + { + NoteRange( nArea != nAct ); + nAct = 0; + } + if( !nFirst ) + nFirst = nArea; + } + else + { + nAct = nArea; + nMin = nA; + nMax = nA; + } +} + +SvLongsPtr TextRanger::GetTextRanges( const Range& rRange ) +{ + DBG_ASSERT( rRange.Min() || rRange.Max(), "Zero-Range not allowed, Bye Bye" ); + USHORT nIndex = 0; + while( nIndex < nCacheSize && rRange != pRangeArr[ nIndex ] ) + ++nIndex; + if( nIndex >= nCacheSize ) + { + ++nCacheIdx; + nCacheIdx %= nCacheSize; + pRangeArr[ nCacheIdx ] = rRange; + if( !pCache[ nCacheIdx ] ) + pCache[ nCacheIdx ] = new SvLongs( 2, 8 ); + nIndex = nCacheIdx; + SvxBoundArgs aArg( this, pCache[ nCacheIdx ], rRange ); + aArg.Calc( *mpPolyPolygon ); + if( mpLinePolyPolygon ) + aArg.Concat( mpLinePolyPolygon ); + } + return pCache[ nIndex ]; +} + +const Rectangle& TextRanger::_GetBoundRect() +{ + DBG_ASSERT( 0 == pBound, "Don't call twice." ); + pBound = new Rectangle( mpPolyPolygon->GetBoundRect() ); + return *pBound; +} + + diff --git a/editeng/source/misc/unolingu.cxx b/editeng/source/misc/unolingu.cxx new file mode 100755 index 000000000000..ae92fd1a01b8 --- /dev/null +++ b/editeng/source/misc/unolingu.cxx @@ -0,0 +1,1377 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <map> +#include <set> +#include <vector> +#include <slist> +#include <memory> +#include <editeng/unolingu.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <rtl/logfile.hxx> +#include <unotools/pathoptions.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/linguistic2/XAvailableLocales.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/util/DateTime.hpp> + +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase1.hxx> // helper for implementations +#include <i18npool/mslangid.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/ucbhelper.hxx> +#include <unotools/localfilehelper.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/content.hxx> +#include <comphelper/processfactory.hxx> +#include <vcl/msgbox.hxx> +#include <tools/shl.hxx> +#include <linguistic/misc.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> + +using namespace ::rtl; +using namespace ::comphelper; +using namespace ::linguistic; +using namespace ::com::sun::star; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::linguistic2; + +#define CSS com::sun::star + +/////////////////////////////////////////////////////////////////////////// + + +static uno::Reference< XLinguServiceManager > GetLngSvcMgr_Impl() +{ + uno::Reference< XLinguServiceManager > xRes; + uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory(); + if (xMgr.is()) + { + xRes = uno::Reference< XLinguServiceManager > ( xMgr->createInstance( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.linguistic2.LinguServiceManager" ) ) ), UNO_QUERY ) ; + } + return xRes; +} + +/////////////////////////////////////////////////////////////////////////// + +BOOL lcl_FindEntry( const OUString &rEntry, const Sequence< OUString > &rCfgSvcs ) +{ + INT32 nRes = -1; + INT32 nEntries = rCfgSvcs.getLength(); + const OUString *pEntry = rCfgSvcs.getConstArray(); + for (INT32 i = 0; i < nEntries && nRes == -1; ++i) + { + if (rEntry == pEntry[i]) + nRes = i; + } + return nRes != -1; +} + + +Sequence< OUString > lcl_RemoveMissingEntries( + const Sequence< OUString > &rCfgSvcs, + const Sequence< OUString > &rAvailSvcs ) +{ + Sequence< OUString > aRes( rCfgSvcs.getLength() ); + OUString *pRes = aRes.getArray(); + INT32 nCnt = 0; + + INT32 nEntries = rCfgSvcs.getLength(); + const OUString *pEntry = rCfgSvcs.getConstArray(); + for (INT32 i = 0; i < nEntries; ++i) + { + if (pEntry[i].getLength() && lcl_FindEntry( pEntry[i], rAvailSvcs )) + pRes[ nCnt++ ] = pEntry[i]; + } + + aRes.realloc( nCnt ); + return aRes; +} + + +Sequence< OUString > lcl_GetLastFoundSvcs( + SvtLinguConfig &rCfg, + const OUString &rLastFoundList , + const Locale &rAvailLocale ) +{ + Sequence< OUString > aRes; + + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + SvxLocaleToLanguage( rAvailLocale ) ) ); + + Sequence< OUString > aNodeNames( rCfg.GetNodeNames(rLastFoundList) ); + BOOL bFound = lcl_FindEntry( aCfgLocaleStr, aNodeNames); + + if (bFound) + { + Sequence< OUString > aNames(1); + OUString &rNodeName = aNames.getArray()[0]; + rNodeName = rLastFoundList; + rNodeName += OUString::valueOf( (sal_Unicode)'/' ); + rNodeName += aCfgLocaleStr; + Sequence< Any > aValues( rCfg.GetProperties( aNames ) ); +#if OSL_DEBUG_LEVEL > 1 + const Any *pValue; + pValue = aValues.getConstArray(); +#endif + if (aValues.getLength()) + { + DBG_ASSERT( aValues.getLength() == 1, "unexpected length of sequence" ); + Sequence< OUString > aSvcImplNames; + if (aValues.getConstArray()[0] >>= aSvcImplNames) + aRes = aSvcImplNames; + else + { + DBG_ERROR( "type mismatch" ); + } + } + } + + return aRes; +} + + +Sequence< OUString > lcl_GetNewEntries( + const Sequence< OUString > &rLastFoundSvcs, + const Sequence< OUString > &rAvailSvcs ) +{ + INT32 nLen = rAvailSvcs.getLength(); + Sequence< OUString > aRes( nLen ); + OUString *pRes = aRes.getArray(); + INT32 nCnt = 0; + + const OUString *pEntry = rAvailSvcs.getConstArray(); + for (INT32 i = 0; i < nLen; ++i) + { + if (pEntry[i].getLength() && !lcl_FindEntry( pEntry[i], rLastFoundSvcs )) + pRes[ nCnt++ ] = pEntry[i]; + } + + aRes.realloc( nCnt ); + return aRes; +} + + +Sequence< OUString > lcl_MergeSeq( + const Sequence< OUString > &rCfgSvcs, + const Sequence< OUString > &rNewSvcs ) +{ + Sequence< OUString > aRes( rCfgSvcs.getLength() + rNewSvcs.getLength() ); + OUString *pRes = aRes.getArray(); + INT32 nCnt = 0; + + for (INT32 k = 0; k < 2; ++k) + { + // add previously configuerd service first and append + // new found services at the end + const Sequence< OUString > &rSeq = k == 0 ? rCfgSvcs : rNewSvcs; + + INT32 nLen = rSeq.getLength(); + const OUString *pEntry = rSeq.getConstArray(); + for (INT32 i = 0; i < nLen; ++i) + { + if (pEntry[i].getLength() && !lcl_FindEntry( pEntry[i], aRes )) + pRes[ nCnt++ ] = pEntry[i]; + } + } + + aRes.realloc( nCnt ); + return aRes; +} + +/////////////////////////////////////////////////////////////////////////// + +// static member initialization +INT16 SvxLinguConfigUpdate::nNeedUpdating = -1; +INT32 SvxLinguConfigUpdate::nCurrentDataFilesChangedCheckValue = -1; + +void SvxLinguConfigUpdate::UpdateAll( sal_Bool bForceCheck ) +{ + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::UpdateAll" ); + + if (IsNeedUpdateAll( bForceCheck )) + { + typedef OUString OUstring_t; + typedef Sequence< OUString > Sequence_OUString_t; + typedef std::vector< OUstring_t > OUString_vector_t; + typedef std::set< OUstring_t > OUString_set_t; + std::vector< OUString_vector_t > aVector; + typedef std::map< OUstring_t, Sequence_OUString_t > list_entry_map_t; + + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::UpdateAll - updating..." ); + + DBG_ASSERT( nNeedUpdating == 1, "SvxLinguConfigUpdate::UpdateAll already updated!" ); + + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + DBG_ASSERT( xLngSvcMgr.is(), "service manager missing"); + if (!xLngSvcMgr.is()) + return; + + SvtLinguConfig aCfg; + + const int nNumServices = 4; + const sal_Char * apServices[nNumServices] = { SN_SPELLCHECKER, SN_GRAMMARCHECKER, SN_HYPHENATOR, SN_THESAURUS }; + const sal_Char * apCurLists[nNumServices] = { "ServiceManager/SpellCheckerList", "ServiceManager/GrammarCheckerList", "ServiceManager/HyphenatorList", "ServiceManager/ThesaurusList" }; + const sal_Char * apLastFoundLists[nNumServices] = { "ServiceManager/LastFoundSpellCheckers", "ServiceManager/LastFoundGrammarCheckers", "ServiceManager/LastFoundHyphenators", "ServiceManager/LastFoundThesauri" }; + + // usage of indices as above: 0 = spell checker, 1 = grammar checker, 2 = hyphenator, 3 = thesaurus + std::vector< list_entry_map_t > aLastFoundSvcs(nNumServices); + std::vector< list_entry_map_t > aCurSvcs(nNumServices); + + for (int k = 0; k < nNumServices; ++k) + { + OUString aService( A2OU( apServices[k] ) ); + OUString aActiveList( A2OU( apCurLists[k] ) ); + OUString aLastFoundList( A2OU( apLastFoundLists[k] ) ); + INT32 i; + + // + // remove configured but not available language/services entries + // + Sequence< OUString > aNodeNames( aCfg.GetNodeNames( aActiveList ) ); // list of configured locales + INT32 nNodeNames = aNodeNames.getLength(); + const OUString *pNodeName = aNodeNames.getConstArray(); + for (i = 0; i < nNodeNames; ++i) + { + Locale aLocale( SvxCreateLocale( MsLangId::convertIsoStringToLanguage(pNodeName[i]) ) ); + Sequence< OUString > aCfgSvcs( + xLngSvcMgr->getConfiguredServices( aService, aLocale )); + Sequence< OUString > aAvailSvcs( + xLngSvcMgr->getAvailableServices( aService, aLocale )); +#if OSL_DEBUG_LEVEL > 1 + const OUString * pCfgSvcs = aCfgSvcs.getConstArray();; + const OUString * pAvailSvcs = aAvailSvcs.getConstArray();; + (void) pCfgSvcs; + (void) pAvailSvcs; +#endif + aCfgSvcs = lcl_RemoveMissingEntries( aCfgSvcs, aAvailSvcs ); + + aCurSvcs[k][ pNodeName[i] ] = aCfgSvcs; + } + + // + // add new available language/servcice entries + // + uno::Reference< XAvailableLocales > xAvail( xLngSvcMgr, UNO_QUERY ); + Sequence< Locale > aAvailLocales( xAvail->getAvailableLocales(aService) ); + INT32 nAvailLocales = aAvailLocales.getLength(); + const Locale *pAvailLocale = aAvailLocales.getConstArray(); + for (i = 0; i < nAvailLocales; ++i) + { + Sequence< OUString > aAvailSvcs( + xLngSvcMgr->getAvailableServices( aService, pAvailLocale[i] )); + Sequence< OUString > aLastSvcs( + lcl_GetLastFoundSvcs( aCfg, aLastFoundList , pAvailLocale[i] )); + Sequence< OUString > aNewSvcs = + lcl_GetNewEntries( aLastSvcs, aAvailSvcs ); +#if OSL_DEBUG_LEVEL > 1 + const OUString * pAvailSvcs = aAvailSvcs.getConstArray(); + const OUString * pLastSvcs = aLastSvcs.getConstArray(); + const OUString * pNewSvcs = aNewSvcs.getConstArray(); + (void) pAvailSvcs; + (void) pLastSvcs; + (void) pNewSvcs; +#endif + + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + SvxLocaleToLanguage( pAvailLocale[i] ) ) ); + Sequence< OUString > aCfgSvcs( aCurSvcs[k][ aCfgLocaleStr ] ); + + // merge services list (previously configured to be listed first). + aCfgSvcs = lcl_MergeSeq( aCfgSvcs, aNewSvcs ); + +/* + // there is at most one Hyphenator per language allowed + // to be configured, thus we only use the first one found. + if (k == 2 && aCfgSvcs.getLength() > 1) + aCfgSvcs.realloc(1); +*/ + aCurSvcs[k][ aCfgLocaleStr ] = aCfgSvcs; + } + + // + // set last found services to currently available ones + // + for (i = 0; i < nAvailLocales; ++i) + { + Sequence< OUString > aSvcImplNames( + xLngSvcMgr->getAvailableServices( aService, pAvailLocale[i] ) ); + +#if OSL_DEBUG_LEVEL > 1 + INT32 nSvcs = aSvcImplNames.getLength(); + const OUString *pSvcImplName = aSvcImplNames.getConstArray(); + for (INT32 j = 0; j < nSvcs; ++j) + { + OUString aImplName( pSvcImplName[j] ); + } +#endif + + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + SvxLocaleToLanguage( pAvailLocale[i] ) ) ); + aLastFoundSvcs[k][ aCfgLocaleStr ] = aSvcImplNames; + } + } + + // + // write new data back to configuration + // + for (int k = 0; k < nNumServices; ++k) + { + for (int i = 0; i < 2; ++i) + { + const sal_Char *pSubNodeName = (i == 0) ? apCurLists[k] : apLastFoundLists[k]; + OUString aSubNodeName( A2OU(pSubNodeName) ); + + list_entry_map_t &rCurMap = (i == 0) ? aCurSvcs[k] : aLastFoundSvcs[k]; + list_entry_map_t::const_iterator aIt( rCurMap.begin() ); + sal_Int32 nVals = static_cast< sal_Int32 >( rCurMap.size() ); + Sequence< PropertyValue > aNewValues( nVals ); + PropertyValue *pNewValue = aNewValues.getArray(); + while (aIt != rCurMap.end()) + { + OUString aCfgEntryName( aSubNodeName ); + aCfgEntryName += OUString::valueOf( (sal_Unicode) '/' ); + aCfgEntryName += (*aIt).first; + +#if OSL_DEBUG_LEVEL > 1 + Sequence< OUString > aSvcImplNames( (*aIt).second ); + INT32 nSvcs = aSvcImplNames.getLength(); + const OUString *pSvcImplName = aSvcImplNames.getConstArray(); + for (INT32 j = 0; j < nSvcs; ++j) + { + OUString aImplName( pSvcImplName[j] ); + } +#endif + pNewValue->Name = aCfgEntryName; + pNewValue->Value <<= (*aIt).second; + ++pNewValue; + ++aIt; + } + DBG_ASSERT( pNewValue - aNewValues.getArray() == nVals, + "possible mismatch of sequence size and property number" ); + + { + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::UpdateAll - ReplaceSetProperties" ); + // add new or replace existing entries. + BOOL bRes = aCfg.ReplaceSetProperties( aSubNodeName, aNewValues ); + if (!bRes) + { +#if OSL_DEBUG_LEVEL > 1 + DBG_ERROR( "failed to set new configuration values" ); +#endif + } + } + } + } + DBG_ASSERT( nCurrentDataFilesChangedCheckValue != -1, "SvxLinguConfigUpdate::UpdateAll DataFilesChangedCheckValue not yet calculated!" ); + Any aAny; + + // for the time being (developer builds until OOo 3.0) + // we should always check for everything available + // otherwise we may miss a new installed extension dicitonary + // just because e.g. the spellchecker is not asked what + // languages it does support currently... + // Since the check is on-demand occuring and executed once it should + // not be too troublesome. + // In OOo 3.0 we will not need the respective code anymore at all. +// aAny <<= nCurrentDataFilesChangedCheckValue; + aAny <<= (INT32) -1; // keep the value set to 'need to check' + + aCfg.SetProperty( A2OU( "DataFilesChangedCheckValue" ), aAny ); + + //! Note 1: the new values are commited when the 'aCfg' object + //! gets destroyed. + //! Note 2: the new settings in the configuration get applied + //! because the 'LngSvcMgr' (in linguistic/source/lngsvcmgr.hxx) + //! listens to the configuration for changes of the relevant + //! properties and then applies the new settings. + + // nothing needs to be done anymore + nNeedUpdating = 0; + } +} + + +INT32 SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue() +{ + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue" ); + + INT32 nHashVal = 0; + // nothing to be checked anymore since those old directory paths are gone by now + return nHashVal; +} + + +BOOL SvxLinguConfigUpdate::IsNeedUpdateAll( sal_Bool bForceCheck ) +{ + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::IsNeedUpdateAll" ); + if (nNeedUpdating == -1 || bForceCheck ) // need to check if updating is necessary + { + // calculate hash value for current data files + nCurrentDataFilesChangedCheckValue = CalcDataFilesChangedCheckValue(); + + // compare hash value and check value to see if anything has changed + // and thus the configuration needs to be updated + SvtLinguOptions aLinguOpt; + SvtLinguConfig aCfg; + aCfg.GetOptions( aLinguOpt ); + nNeedUpdating = (nCurrentDataFilesChangedCheckValue == aLinguOpt.nDataFilesChangedCheckValue) ? 0 : 1; + } + DBG_ASSERT( nNeedUpdating != -1, + "need for linguistic configuration update should have been already checked." ); + + return nNeedUpdating == 1; +} + +/////////////////////////////////////////////////////////////////////////// + + +//! Dummy implementation in order to avoid loading of lingu DLL +//! when only the XSupportedLocales interface is used. +//! The dummy accesses the real implementation (and thus loading the DLL) +//! when "real" work needs to be done only. +class ThesDummy_Impl : + public cppu::WeakImplHelper1< XThesaurus > +{ + uno::Reference< XThesaurus > xThes; // the real one... + Sequence< Locale > *pLocaleSeq; + + void GetCfgLocales(); + + void GetThes_Impl(); + +public: + ThesDummy_Impl() : pLocaleSeq(0) {} + ~ThesDummy_Impl(); + + // XSupportedLocales + virtual ::com::sun::star::uno::Sequence< + ::com::sun::star::lang::Locale > SAL_CALL + getLocales() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL + hasLocale( const ::com::sun::star::lang::Locale& rLocale ) + throw(::com::sun::star::uno::RuntimeException); + + // XThesaurus + virtual ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XMeaning > > SAL_CALL + queryMeanings( const ::rtl::OUString& rTerm, + const ::com::sun::star::lang::Locale& rLocale, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); +}; + + +ThesDummy_Impl::~ThesDummy_Impl() +{ + delete pLocaleSeq; +} + + +void ThesDummy_Impl::GetCfgLocales() +{ + if (!pLocaleSeq) + { + SvtLinguConfig aCfg; + String aNode( A2OU( "ServiceManager/ThesaurusList" ) ); + Sequence < OUString > aNodeNames( aCfg.GetNodeNames( aNode ) ); + const OUString *pNodeNames = aNodeNames.getConstArray(); + INT32 nLen = aNodeNames.getLength(); + pLocaleSeq = new Sequence< Locale >( nLen ); + Locale *pLocale = pLocaleSeq->getArray(); + for (INT32 i = 0; i < nLen; ++i) + { + pLocale[i] = SvxCreateLocale( + MsLangId::convertIsoStringToLanguage( pNodeNames[i] ) ); + } + } +} + + +void ThesDummy_Impl::GetThes_Impl() +{ + // update configuration before accessing the service + if (SvxLinguConfigUpdate::IsNeedUpdateAll()) + SvxLinguConfigUpdate::UpdateAll(); + + if (!xThes.is()) + { + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + if (xLngSvcMgr.is()) + xThes = xLngSvcMgr->getThesaurus(); + + if (xThes.is()) + { + // no longer needed... + delete pLocaleSeq; pLocaleSeq = 0; + } + } +} + + +uno::Sequence< lang::Locale > SAL_CALL + ThesDummy_Impl::getLocales() + throw(uno::RuntimeException) +{ + if (!SvxLinguConfigUpdate::IsNeedUpdateAll()) // configuration already update and thus lingu DLL's already loaded ? + GetThes_Impl(); + if (xThes.is()) + return xThes->getLocales(); + else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now + GetCfgLocales(); + return *pLocaleSeq; +} + + +sal_Bool SAL_CALL + ThesDummy_Impl::hasLocale( const lang::Locale& rLocale ) + throw(uno::RuntimeException) +{ + if (!SvxLinguConfigUpdate::IsNeedUpdateAll()) // configuration already update and thus lingu DLL's already loaded ? + GetThes_Impl(); + if (xThes.is()) + return xThes->hasLocale( rLocale ); + else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now + GetCfgLocales(); + GetCfgLocales(); + BOOL bFound = FALSE; + INT32 nLen = pLocaleSeq->getLength(); + const Locale *pLocale = pLocaleSeq->getConstArray(); + const Locale *pEnd = pLocale + nLen; + for ( ; pLocale < pEnd && !bFound; ++pLocale) + { + bFound = pLocale->Language == rLocale.Language && + pLocale->Country == rLocale.Country && + pLocale->Variant == rLocale.Variant; + } + return bFound; +} + + +uno::Sequence< uno::Reference< linguistic2::XMeaning > > SAL_CALL + ThesDummy_Impl::queryMeanings( + const rtl::OUString& rTerm, + const lang::Locale& rLocale, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetThes_Impl(); + uno::Sequence< uno::Reference< linguistic2::XMeaning > > aRes; + DBG_ASSERT( xThes.is(), "Thesaurus missing" ); + if (xThes.is()) + aRes = xThes->queryMeanings( rTerm, rLocale, rProperties ); + return aRes; +} + + +/////////////////////////////////////////////////////////////////////////// + + +//! Dummy implementation in order to avoid loading of lingu DLL. +//! The dummy accesses the real implementation (and thus loading the DLL) +//! when it needs to be done only. +class SpellDummy_Impl : + public cppu::WeakImplHelper1< XSpellChecker1 > +{ + uno::Reference< XSpellChecker1 > xSpell; // the real one... + + void GetSpell_Impl(); + +public: + + // XSupportedLanguages (for XSpellChecker1) + virtual ::com::sun::star::uno::Sequence< sal_Int16 > SAL_CALL + getLanguages() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL + hasLanguage( sal_Int16 nLanguage ) + throw(::com::sun::star::uno::RuntimeException); + + // XSpellChecker1 (same as XSpellChecker but sal_Int16 for language) + virtual sal_Bool SAL_CALL + isValid( const ::rtl::OUString& rWord, sal_Int16 nLanguage, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellAlternatives > SAL_CALL + spell( const ::rtl::OUString& rWord, sal_Int16 nLanguage, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); +}; + + +void SpellDummy_Impl::GetSpell_Impl() +{ + // update configuration before accessing the service + if (SvxLinguConfigUpdate::IsNeedUpdateAll()) + SvxLinguConfigUpdate::UpdateAll(); + + if (!xSpell.is()) + { + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + if (xLngSvcMgr.is()) + xSpell = uno::Reference< XSpellChecker1 >( xLngSvcMgr->getSpellChecker(), UNO_QUERY ); + } +} + + +uno::Sequence< sal_Int16 > SAL_CALL + SpellDummy_Impl::getLanguages() + throw(uno::RuntimeException) +{ + GetSpell_Impl(); + if (xSpell.is()) + return xSpell->getLanguages(); + else + return uno::Sequence< sal_Int16 >(); +} + + +sal_Bool SAL_CALL + SpellDummy_Impl::hasLanguage( sal_Int16 nLanguage ) + throw(uno::RuntimeException) +{ + GetSpell_Impl(); + BOOL bRes = FALSE; + if (xSpell.is()) + bRes = xSpell->hasLanguage( nLanguage ); + return bRes; +} + + +sal_Bool SAL_CALL + SpellDummy_Impl::isValid( const rtl::OUString& rWord, sal_Int16 nLanguage, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetSpell_Impl(); + BOOL bRes = TRUE; + if (xSpell.is()) + bRes = xSpell->isValid( rWord, nLanguage, rProperties ); + return bRes; +} + + +uno::Reference< linguistic2::XSpellAlternatives > SAL_CALL + SpellDummy_Impl::spell( const rtl::OUString& rWord, sal_Int16 nLanguage, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetSpell_Impl(); + uno::Reference< linguistic2::XSpellAlternatives > xRes; + if (xSpell.is()) + xRes = xSpell->spell( rWord, nLanguage, rProperties ); + return xRes; +} + + +/////////////////////////////////////////////////////////////////////////// + + +//! Dummy implementation in order to avoid loading of lingu DLL. +//! The dummy accesses the real implementation (and thus loading the DLL) +//! when it needs to be done only. +class HyphDummy_Impl : + public cppu::WeakImplHelper1< XHyphenator > +{ + uno::Reference< XHyphenator > xHyph; // the real one... + + void GetHyph_Impl(); + +public: + + // XSupportedLocales + virtual ::com::sun::star::uno::Sequence< + ::com::sun::star::lang::Locale > SAL_CALL + getLocales() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL + hasLocale( const ::com::sun::star::lang::Locale& rLocale ) + throw(::com::sun::star::uno::RuntimeException); + + // XHyphenator + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenatedWord > SAL_CALL + hyphenate( const ::rtl::OUString& rWord, + const ::com::sun::star::lang::Locale& rLocale, + sal_Int16 nMaxLeading, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenatedWord > SAL_CALL + queryAlternativeSpelling( const ::rtl::OUString& rWord, + const ::com::sun::star::lang::Locale& rLocale, + sal_Int16 nIndex, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XPossibleHyphens > SAL_CALL + createPossibleHyphens( + const ::rtl::OUString& rWord, + const ::com::sun::star::lang::Locale& rLocale, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); +}; + + +void HyphDummy_Impl::GetHyph_Impl() +{ + // update configuration before accessing the service + if (SvxLinguConfigUpdate::IsNeedUpdateAll()) + SvxLinguConfigUpdate::UpdateAll(); + + if (!xHyph.is()) + { + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + if (xLngSvcMgr.is()) + xHyph = xLngSvcMgr->getHyphenator(); + } +} + + +uno::Sequence< lang::Locale > SAL_CALL + HyphDummy_Impl::getLocales() + throw(uno::RuntimeException) +{ + GetHyph_Impl(); + if (xHyph.is()) + return xHyph->getLocales(); + else + return uno::Sequence< lang::Locale >(); +} + + +sal_Bool SAL_CALL + HyphDummy_Impl::hasLocale( const lang::Locale& rLocale ) + throw(uno::RuntimeException) +{ + GetHyph_Impl(); + BOOL bRes = FALSE; + if (xHyph.is()) + bRes = xHyph->hasLocale( rLocale ); + return bRes; +} + + +uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL + HyphDummy_Impl::hyphenate( + const rtl::OUString& rWord, + const lang::Locale& rLocale, + sal_Int16 nMaxLeading, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetHyph_Impl(); + uno::Reference< linguistic2::XHyphenatedWord > xRes; + if (xHyph.is()) + xRes = xHyph->hyphenate( rWord, rLocale, nMaxLeading, rProperties ); + return xRes; +} + + +uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL + HyphDummy_Impl::queryAlternativeSpelling( + const rtl::OUString& rWord, + const lang::Locale& rLocale, + sal_Int16 nIndex, + const PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetHyph_Impl(); + uno::Reference< linguistic2::XHyphenatedWord > xRes; + if (xHyph.is()) + xRes = xHyph->queryAlternativeSpelling( rWord, rLocale, nIndex, rProperties ); + return xRes; +} + + +uno::Reference< linguistic2::XPossibleHyphens > SAL_CALL + HyphDummy_Impl::createPossibleHyphens( + const rtl::OUString& rWord, + const lang::Locale& rLocale, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetHyph_Impl(); + uno::Reference< linguistic2::XPossibleHyphens > xRes; + if (xHyph.is()) + xRes = xHyph->createPossibleHyphens( rWord, rLocale, rProperties ); + return xRes; +} + + +/////////////////////////////////////////////////////////////////////////// + + +typedef cppu::WeakImplHelper1 < XEventListener > LinguMgrAppExitLstnrBaseClass; + +class LinguMgrAppExitLstnr : public LinguMgrAppExitLstnrBaseClass +{ + uno::Reference< XComponent > xDesktop; + +public: + LinguMgrAppExitLstnr(); + virtual ~LinguMgrAppExitLstnr(); + + virtual void AtExit() = 0; + + + // lang::XEventListener + virtual void SAL_CALL disposing(const EventObject& rSource) + throw( RuntimeException ); +}; + +LinguMgrAppExitLstnr::LinguMgrAppExitLstnr() +{ + // add object to frame::Desktop EventListeners in order to properly call + // the AtExit function at appliction exit. + + uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory(); + if ( xMgr.is() ) + { + xDesktop = uno::Reference< XComponent > ( xMgr->createInstance( + OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.frame.Desktop" ) ) ), UNO_QUERY ) ; + if (xDesktop.is()) + xDesktop->addEventListener( this ); + } +} + +LinguMgrAppExitLstnr::~LinguMgrAppExitLstnr() +{ + if (xDesktop.is()) + { + xDesktop->removeEventListener( this ); + xDesktop = NULL; //! release reference to desktop + } + DBG_ASSERT(!xDesktop.is(), "reference to desktop should be realeased"); +} + +void LinguMgrAppExitLstnr::disposing(const EventObject& rSource) + throw( RuntimeException ) +{ + if (xDesktop.is() && rSource.Source == xDesktop) + { + xDesktop->removeEventListener( this ); + xDesktop = NULL; //! release reference to desktop + + AtExit(); + } +} + +/////////////////////////////////////////////////////////////////////////// + +class LinguMgrExitLstnr : public LinguMgrAppExitLstnr +{ +public: + virtual void AtExit(); +}; + +void LinguMgrExitLstnr::AtExit() +{ + // release references + LinguMgr::xLngSvcMgr = 0; + LinguMgr::xSpell = 0; + LinguMgr::xHyph = 0; + LinguMgr::xThes = 0; + LinguMgr::xDicList = 0; + LinguMgr::xProp = 0; + LinguMgr::xIgnoreAll = 0; + LinguMgr::xChangeAll = 0; + + LinguMgr::bExiting = sal_True; + + //TL:TODO: MBA fragen wie ich ohne Absturz hier meinen Speicher + // wieder freibekomme... + //delete LinguMgr::pExitLstnr; + LinguMgr::pExitLstnr = 0; +} + +/////////////////////////////////////////////////////////////////////////// + + +// static member initialization +LinguMgrExitLstnr * LinguMgr::pExitLstnr = 0; +sal_Bool LinguMgr::bExiting = sal_False; +uno::Reference< XLinguServiceManager > LinguMgr::xLngSvcMgr = 0; +uno::Reference< XSpellChecker1 > LinguMgr::xSpell = 0; +uno::Reference< XHyphenator > LinguMgr::xHyph = 0; +uno::Reference< XThesaurus > LinguMgr::xThes = 0; +uno::Reference< XDictionaryList > LinguMgr::xDicList = 0; +uno::Reference< XPropertySet > LinguMgr::xProp = 0; +uno::Reference< XDictionary > LinguMgr::xIgnoreAll = 0; +uno::Reference< XDictionary > LinguMgr::xChangeAll = 0; + + +uno::Reference< XLinguServiceManager > LinguMgr::GetLngSvcMgr() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + return xLngSvcMgr; +} + + +uno::Reference< XSpellChecker1 > LinguMgr::GetSpellChecker() +{ + return xSpell.is() ? xSpell : GetSpell(); +} + +uno::Reference< XHyphenator > LinguMgr::GetHyphenator() +{ + return xHyph.is() ? xHyph : GetHyph(); +} + +uno::Reference< XThesaurus > LinguMgr::GetThesaurus() +{ + return xThes.is() ? xThes : GetThes(); +} + +uno::Reference< XDictionaryList > LinguMgr::GetDictionaryList() +{ + return xDicList.is() ? xDicList : GetDicList(); +} + +uno::Reference< XPropertySet > LinguMgr::GetLinguPropertySet() +{ + return xProp.is() ? xProp : GetProp(); +} + +uno::Reference< XDictionary > LinguMgr::GetStandardDic() +{ + //! don't hold reference to this + //! (it may be removed from dictionary list and needs to be + //! created empty if accessed again) + return GetStandard(); +} + +uno::Reference< XDictionary > LinguMgr::GetIgnoreAllList() +{ + return xIgnoreAll.is() ? xIgnoreAll : GetIgnoreAll(); +} + +uno::Reference< XDictionary > LinguMgr::GetChangeAllList() +{ + return xChangeAll.is() ? xChangeAll : GetChangeAll(); +} + +uno::Reference< XSpellChecker1 > LinguMgr::GetSpell() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + //! use dummy implementation in order to avoid loading of lingu DLL + xSpell = new SpellDummy_Impl; + +/* if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + if (xLngSvcMgr.is()) + { + xSpell = uno::Reference< XSpellChecker1 > ( + xLngSvcMgr->getSpellChecker(), UNO_QUERY ); + } +*/ + return xSpell; +} + +uno::Reference< XHyphenator > LinguMgr::GetHyph() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + //! use dummy implementation in order to avoid loading of lingu DLL + xHyph = new HyphDummy_Impl; + +/* + if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + if (xLngSvcMgr.is()) + { + xHyph = xLngSvcMgr->getHyphenator(); + } +*/ + return xHyph; +} + +uno::Reference< XThesaurus > LinguMgr::GetThes() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + //! use dummy implementation in order to avoid loading of lingu DLL + //! when only the XSupportedLocales interface is used. + //! The dummy accesses the real implementation (and thus loading the DLL) + //! when "real" work needs to be done only. + xThes = new ThesDummy_Impl; +/* + if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + if (xLngSvcMgr.is()) + { + xThes = xLngSvcMgr->getThesaurus(); + } +*/ + return xThes; +} + + +void LinguMgr::UpdateAll() +{ +} + + +uno::Reference< XDictionaryList > LinguMgr::GetDicList() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); + if (xMgr.is()) + { + xDicList = uno::Reference< XDictionaryList > ( xMgr->createInstance( + A2OU("com.sun.star.linguistic2.DictionaryList") ), UNO_QUERY ); + } + return xDicList; +} + +uno::Reference< XPropertySet > LinguMgr::GetProp() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); + if (xMgr.is()) + { + xProp = uno::Reference< XPropertySet > ( xMgr->createInstance( + A2OU("com.sun.star.linguistic2.LinguProperties") ), UNO_QUERY ); + } + return xProp; +} + +uno::Reference< XDictionary > LinguMgr::GetIgnoreAll() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XDictionaryList > xTmpDicList( GetDictionaryList() ); + if (xTmpDicList.is()) + { + xIgnoreAll = uno::Reference< XDictionary > ( xTmpDicList->getDictionaryByName( + A2OU("IgnoreAllList") ), UNO_QUERY ); + } + return xIgnoreAll; +} + +uno::Reference< XDictionary > LinguMgr::GetChangeAll() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XDictionaryList > _xDicList( GetDictionaryList() , UNO_QUERY ); + if (_xDicList.is()) + { + xChangeAll = uno::Reference< XDictionary > ( + _xDicList->createDictionary( + A2OU("ChangeAllList"), + SvxCreateLocale( LANGUAGE_NONE ), + DictionaryType_NEGATIVE, String() ), UNO_QUERY ); + } + return xChangeAll; +} + +uno::Reference< XDictionary > LinguMgr::GetStandard() +{ + // Tries to return a dictionary which may hold positive entries is + // persistent and not read-only. + + if (bExiting) + return 0; + + uno::Reference< XDictionaryList > xTmpDicList( GetDictionaryList() ); + if (!xTmpDicList.is()) + return NULL; + + const OUString aDicName( RTL_CONSTASCII_USTRINGPARAM( "standard.dic" ) ); + uno::Reference< XDictionary > xDic( xTmpDicList->getDictionaryByName( aDicName ), + UNO_QUERY ); + if (!xDic.is()) + { + // try to create standard dictionary + uno::Reference< XDictionary > xTmp; + try + { + xTmp = xTmpDicList->createDictionary( aDicName, + SvxCreateLocale( LANGUAGE_NONE ), + DictionaryType_POSITIVE, + linguistic::GetWritableDictionaryURL( aDicName ) ); + } + catch(com::sun::star::uno::Exception &) + { + } + + // add new dictionary to list + if (xTmp.is()) + { + xTmpDicList->addDictionary( xTmp ); + xTmp->setActive( sal_True ); + } + xDic = uno::Reference< XDictionary > ( xTmp, UNO_QUERY ); + } +#if OSL_DEBUG_LEVEL > 1 + uno::Reference< XStorable > xStor( xDic, UNO_QUERY ); + DBG_ASSERT( xDic.is() && xDic->getDictionaryType() == DictionaryType_POSITIVE, + "wrong dictionary type"); + DBG_ASSERT( xDic.is() && SvxLocaleToLanguage( xDic->getLocale() ) == LANGUAGE_NONE, + "wrong dictionary language"); + DBG_ASSERT( !xStor.is() || (xStor->hasLocation() && !xStor->isReadonly()), + "dictionary not editable" ); +#endif + + return xDic; +} + +/////////////////////////////////////////////////////////////////////////// + +uno::Reference< XSpellChecker1 > SvxGetSpellChecker() +{ + return LinguMgr::GetSpellChecker(); +} + +uno::Reference< XHyphenator > SvxGetHyphenator() +{ + return LinguMgr::GetHyphenator(); +} + +uno::Reference< XThesaurus > SvxGetThesaurus() +{ + return LinguMgr::GetThesaurus(); +} + +uno::Reference< XDictionaryList > SvxGetDictionaryList() +{ + return LinguMgr::GetDictionaryList(); +} + +uno::Reference< XPropertySet > SvxGetLinguPropertySet() +{ + return LinguMgr::GetLinguPropertySet(); +} + +//TL:TODO: remove argument or provide SvxGetIgnoreAllList with the same one +uno::Reference< XDictionary > SvxGetOrCreatePosDic( + uno::Reference< XDictionaryList > /* xDicList */ ) +{ + return LinguMgr::GetStandardDic(); +} + +uno::Reference< XDictionary > SvxGetIgnoreAllList() +{ + return LinguMgr::GetIgnoreAllList(); +} + +uno::Reference< XDictionary > SvxGetChangeAllList() +{ + return LinguMgr::GetChangeAllList(); +} + +/////////////////////////////////////////////////////////////////////////// + + +#include <com/sun/star/linguistic2/XHyphenatedWord.hpp> + +SvxAlternativeSpelling SvxGetAltSpelling( + const ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenatedWord > & rHyphWord ) +{ + SvxAlternativeSpelling aRes; + if (rHyphWord.is() && rHyphWord->isAlternativeSpelling()) + { + OUString aWord( rHyphWord->getWord() ), + aAltWord( rHyphWord->getHyphenatedWord() ); + INT16 nHyphenationPos = rHyphWord->getHyphenationPos(), + nHyphenPos = rHyphWord->getHyphenPos(); + INT16 nLen = (INT16)aWord.getLength(); + INT16 nAltLen = (INT16)aAltWord.getLength(); + const sal_Unicode *pWord = aWord.getStr(), + *pAltWord = aAltWord.getStr(); + + // count number of chars from the left to the + // hyphenation pos / hyphen pos that are equal + INT16 nL = 0; + while (nL <= nHyphenationPos && nL <= nHyphenPos + && pWord[ nL ] == pAltWord[ nL ]) + ++nL; + // count number of chars from the right to the + // hyphenation pos / hyphen pos that are equal + INT16 nR = 0; + INT32 nIdx = nLen - 1; + INT32 nAltIdx = nAltLen - 1; + while (nIdx > nHyphenationPos && nAltIdx > nHyphenPos + && pWord[ nIdx-- ] == pAltWord[ nAltIdx-- ]) + ++nR; + + aRes.aReplacement = OUString( aAltWord.copy( nL, nAltLen - nL - nR ) ); + aRes.nChangedPos = (INT16) nL; + aRes.nChangedLength = nLen - nL - nR; + aRes.bIsAltSpelling = TRUE; + aRes.xHyphWord = rHyphWord; + } + return aRes; +} + + +/////////////////////////////////////////////////////////////////////////// + +SvxDicListChgClamp::SvxDicListChgClamp( uno::Reference< XDictionaryList > &rxDicList ) : + xDicList ( rxDicList ) +{ + if (xDicList.is()) + { + xDicList->beginCollectEvents(); + } +} + +SvxDicListChgClamp::~SvxDicListChgClamp() +{ + if (xDicList.is()) + { + xDicList->endCollectEvents(); + } +} + +/////////////////////////////////////////////////////////////////////////// + +short SvxDicError( Window *pParent, sal_Int16 nError ) +{ + short nRes = 0; + if (DIC_ERR_NONE != nError) + { + int nRid; + switch (nError) + { + case DIC_ERR_FULL : nRid = RID_SVXSTR_DIC_ERR_FULL; break; + case DIC_ERR_READONLY : nRid = RID_SVXSTR_DIC_ERR_READONLY; break; + default: + nRid = RID_SVXSTR_DIC_ERR_UNKNOWN; + DBG_ASSERT(0, "unexpected case"); + } + nRes = InfoBox( pParent, EE_RESSTR( nRid ) ).Execute(); + } + return nRes; +} + +LanguageType SvxLocaleToLanguage( const Locale& rLocale ) +{ + // empty Locale -> LANGUAGE_NONE + if ( rLocale.Language.getLength() == 0 ) + return LANGUAGE_NONE; + + return MsLangId::convertLocaleToLanguage( rLocale ); +} + +Locale& SvxLanguageToLocale( Locale& rLocale, LanguageType eLang ) +{ + if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */) + MsLangId::convertLanguageToLocale( eLang, rLocale ); + else + rLocale = Locale(); + + return rLocale; +} + +Locale SvxCreateLocale( LanguageType eLang ) +{ + Locale aLocale; + if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */) + MsLangId::convertLanguageToLocale( eLang, aLocale ); + + return aLocale; +} + + |