diff -ru libreoffice-3.5.5.3.orig/cui/source/options/optlingu.cxx libreoffice-3.5.5.3/cui/source/options/optlingu.cxx --- libreoffice-3.5.5.3.orig/cui/source/options/optlingu.cxx 2012-07-13 12:37:15.032259144 +0100 +++ libreoffice-3.5.5.3/cui/source/options/optlingu.cxx 2012-07-16 08:49:26.294209540 +0100 @@ -1150,12 +1150,6 @@ aLinguDicsEditPB.SetAccessibleName(sAccessibleNameDicsEdit); aLinguOptionsEditPB.SetAccessibleName(sAccessibleNameOptionEdit); - // force recalculation of hash value used for checking the need of updating - // because new dictionaries might be installed / downloaded. - //! Thus it needs to be called now since it may infuence the supported languages - //! to be reported AND the found user-dictionaries(!) as well. - SvxLinguConfigUpdate::UpdateAll( sal_True ); - xProp = uno::Reference< XPropertySet >( SvxGetLinguPropertySet(), UNO_QUERY ); xDicList = uno::Reference< XDictionaryList >( SvxGetDictionaryList(), UNO_QUERY ); if (xDicList.is()) diff -ru libreoffice-3.5.5.3.orig/editeng/inc/editeng/unolingu.hxx libreoffice-3.5.5.3/editeng/inc/editeng/unolingu.hxx --- libreoffice-3.5.5.3.orig/editeng/inc/editeng/unolingu.hxx 2012-07-13 12:37:16.109269892 +0100 +++ libreoffice-3.5.5.3/editeng/inc/editeng/unolingu.hxx 2012-07-16 08:49:26.294209540 +0100 @@ -46,29 +46,6 @@ class Window; /////////////////////////////////////////////////////////////////////////// -// SvxLinguConfigUpdate -// class to update configuration items when (before!) the linguistic is used. -// -// This class is called by all the dummy implementations to update all of the -// configuration (list of used/available services) when the linguistic is -// accessed for the first time. - -class SvxLinguConfigUpdate -{ - static sal_Int32 nCurrentDataFilesChangedCheckValue; - static sal_Int16 nNeedUpdating; // n == -1 => needs to be checked - // n == 0 => already updated, nothing to be done - // n == 1 => needs to be updated - - static sal_Int32 CalcDataFilesChangedCheckValue(); - -public: - - EDITENG_DLLPUBLIC static void UpdateAll( sal_Bool bForceCheck = sal_False ); - static sal_Bool IsNeedUpdateAll( sal_Bool bForceCheck = sal_False ); -}; - -/////////////////////////////////////////////////////////////////////////// class EDITENG_DLLPUBLIC LinguMgr { diff -ru libreoffice-3.5.5.3.orig/editeng/source/misc/unolingu.cxx libreoffice-3.5.5.3/editeng/source/misc/unolingu.cxx --- libreoffice-3.5.5.3.orig/editeng/source/misc/unolingu.cxx 2012-07-13 12:37:15.900267806 +0100 +++ libreoffice-3.5.5.3/editeng/source/misc/unolingu.cxx 2012-07-16 08:52:53.919596778 +0100 @@ -90,365 +90,6 @@ return xRes; } -sal_Bool lcl_FindEntry( const OUString &rEntry, const Sequence< OUString > &rCfgSvcs ) -{ - sal_Int32 nRes = -1; - sal_Int32 nEntries = rCfgSvcs.getLength(); - const OUString *pEntry = rCfgSvcs.getConstArray(); - for (sal_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(); - sal_Int32 nCnt = 0; - - sal_Int32 nEntries = rCfgSvcs.getLength(); - const OUString *pEntry = rCfgSvcs.getConstArray(); - for (sal_Int32 i = 0; i < nEntries; ++i) - { - if (!pEntry[i].isEmpty() && 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) ); - sal_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 (aValues.getLength()) - { - OSL_ENSURE( aValues.getLength() == 1, "unexpected length of sequence" ); - Sequence< OUString > aSvcImplNames; - if (aValues.getConstArray()[0] >>= aSvcImplNames) - aRes = aSvcImplNames; - else - { - OSL_FAIL( "type mismatch" ); - } - } - } - - return aRes; -} - - -Sequence< OUString > lcl_GetNewEntries( - const Sequence< OUString > &rLastFoundSvcs, - const Sequence< OUString > &rAvailSvcs ) -{ - sal_Int32 nLen = rAvailSvcs.getLength(); - Sequence< OUString > aRes( nLen ); - OUString *pRes = aRes.getArray(); - sal_Int32 nCnt = 0; - - const OUString *pEntry = rAvailSvcs.getConstArray(); - for (sal_Int32 i = 0; i < nLen; ++i) - { - if (!pEntry[i].isEmpty() && !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(); - sal_Int32 nCnt = 0; - - for (sal_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; - - sal_Int32 nLen = rSeq.getLength(); - const OUString *pEntry = rSeq.getConstArray(); - for (sal_Int32 i = 0; i < nLen; ++i) - { - if (!pEntry[i].isEmpty() && !lcl_FindEntry( pEntry[i], aRes )) - pRes[ nCnt++ ] = pEntry[i]; - } - } - - aRes.realloc( nCnt ); - return aRes; -} - -sal_Int16 SvxLinguConfigUpdate::nNeedUpdating = -1; -sal_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::map< OUstring_t, Sequence_OUString_t > list_entry_map_t; - - RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::UpdateAll - updating..." ); - - OSL_ENSURE( nNeedUpdating == 1, "SvxLinguConfigUpdate::UpdateAll already updated!" ); - - uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); - OSL_ENSURE( 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( ::rtl::OUString::createFromAscii( apServices[k] ) ); - OUString aActiveList( ::rtl::OUString::createFromAscii( apCurLists[k] ) ); - OUString aLastFoundList( ::rtl::OUString::createFromAscii( apLastFoundLists[k] ) ); - sal_Int32 i; - - // - // remove configured but not available language/services entries - // - Sequence< OUString > aNodeNames( aCfg.GetNodeNames( aActiveList ) ); // list of configured locales - sal_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) ); - sal_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 - sal_Int32 nSvcs = aSvcImplNames.getLength(); - const OUString *pSvcImplName = aSvcImplNames.getConstArray(); - for (sal_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( ::rtl::OUString::createFromAscii(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 ); - sal_Int32 nSvcs = aSvcImplNames.getLength(); - const OUString *pSvcImplName = aSvcImplNames.getConstArray(); - for (sal_Int32 j = 0; j < nSvcs; ++j) - { - OUString aImplName( pSvcImplName[j] ); - } -#endif - pNewValue->Name = aCfgEntryName; - pNewValue->Value <<= (*aIt).second; - ++pNewValue; - ++aIt; - } - OSL_ENSURE( 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. - sal_Bool bRes = aCfg.ReplaceSetProperties( aSubNodeName, aNewValues ); - if (!bRes) - { -#if OSL_DEBUG_LEVEL > 1 - OSL_FAIL( "failed to set new configuration values" ); -#endif - } - } - } - } - OSL_ENSURE( 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 <<= (sal_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; - } -} - - -sal_Int32 SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue() -{ - RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue" ); - - sal_Int32 nHashVal = 0; - // nothing to be checked anymore since those old directory paths are gone by now - return nHashVal; -} - - -sal_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; - } - OSL_ENSURE( 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. @@ -520,10 +158,6 @@ 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() ); @@ -543,8 +177,7 @@ ThesDummy_Impl::getLocales() throw(uno::RuntimeException) { - if (!SvxLinguConfigUpdate::IsNeedUpdateAll()) // configuration already update and thus lingu DLL's already loaded ? - GetThes_Impl(); + GetThes_Impl(); if (xThes.is()) return xThes->getLocales(); else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now @@ -557,8 +190,7 @@ 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(); + GetThes_Impl(); if (xThes.is()) return xThes->hasLocale( rLocale ); else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now @@ -632,10 +264,6 @@ 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() ); @@ -748,10 +376,6 @@ 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() ); diff -ru libreoffice-3.5.5.3.orig/linguistic/Library_lng.mk libreoffice-3.5.5.3/linguistic/Library_lng.mk --- libreoffice-3.5.5.3.orig/linguistic/Library_lng.mk 2012-07-13 12:23:35.568866084 +0100 +++ libreoffice-3.5.5.3/linguistic/Library_lng.mk 2012-07-16 08:49:27.810226966 +0100 @@ -56,6 +56,7 @@ tl \ ucbhelper \ utl \ + vcl \ xo \ $(gb_STDLIBS) \ )) diff -ru libreoffice-3.5.5.3.orig/linguistic/prj/build.lst libreoffice-3.5.5.3/linguistic/prj/build.lst --- libreoffice-3.5.5.3.orig/linguistic/prj/build.lst 2012-07-13 12:23:35.611866523 +0100 +++ libreoffice-3.5.5.3/linguistic/prj/build.lst 2012-07-16 08:49:27.820227082 +0100 @@ -1,2 +1,2 @@ -lg linguistic : svl xmloff ucbhelper comphelper ICU:icu LIBXSLT:libxslt NULL +lg linguistic : svl vcl xmloff ucbhelper comphelper ICU:icu LIBXSLT:libxslt NULL lg linguistic\prj nmake - all lg_prj NULL diff -ru libreoffice-3.5.5.3.orig/linguistic/source/lngsvcmgr.cxx libreoffice-3.5.5.3/linguistic/source/lngsvcmgr.cxx --- libreoffice-3.5.5.3.orig/linguistic/source/lngsvcmgr.cxx 2012-07-13 12:23:35.585866257 +0100 +++ libreoffice-3.5.5.3/linguistic/source/lngsvcmgr.cxx 2012-07-16 08:49:27.829227184 +0100 @@ -27,6 +27,7 @@ ************************************************************************/ +#include #include #include #include @@ -270,8 +271,6 @@ } } - -//IMPL_LINK( LngSvcMgrListenerHelper, TimeOut, Timer*, pTimer ) long LngSvcMgrListenerHelper::Timeout() { osl::MutexGuard aGuard( GetLinguMutex() ); @@ -483,11 +482,98 @@ pNames[2] = "ServiceManager/HyphenatorList"; pNames[3] = "ServiceManager/ThesaurusList"; EnableNotification( aNames ); + + UpdateAll(); + + aUpdateTimer.SetTimeout(500); + aUpdateTimer.SetTimeoutHdl(LINK(this, LngSvcMgr, updateAndBroadcast)); + + // request to be notified if an extension has been added/removed + uno::Reference xContext(comphelper::getProcessComponentContext()); + + uno::Reference xExtensionManager( + deployment::ExtensionManager::get(xContext)); + if (xExtensionManager.is()) + { + xMB = uno::Reference(xExtensionManager, uno::UNO_QUERY_THROW); + + uno::Reference xListener(this); + xMB->addModifyListener( xListener ); + } +} + +// ::com::sun::star::util::XModifyListener +void LngSvcMgr::modified(const lang::EventObject&) + throw(uno::RuntimeException) +{ + osl::MutexGuard aGuard(GetLinguMutex()); + //assume that if an extension has been added/removed that + //it might be a dictionary extension, so drop our cache + + delete pAvailSpellSvcs; + pAvailSpellSvcs = NULL; + delete pAvailGrammarSvcs; + pAvailGrammarSvcs = NULL; + delete pAvailHyphSvcs; + pAvailHyphSvcs = NULL; + delete pAvailThesSvcs; + pAvailThesSvcs = NULL; + + //schedule in an update to execute in the main thread + aUpdateTimer.Start(); +} + +//run update, and inform everyone that dictionaries (may) have changed, this +//needs to be run in the main thread because +//utl::ConfigChangeListener_Impl::changesOccurred grabs the SolarMutex and we +//get notified that an extension was added from an extension manager thread +IMPL_LINK_NOARG(LngSvcMgr, updateAndBroadcast) +{ + osl::MutexGuard aGuard( GetLinguMutex() ); + + UpdateAll(); + + if (pListenerHelper) + { + pListenerHelper->AddLngSvcEvt( + linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN | + linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN | + linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN | + linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN ); + } + + return 0; } +void LngSvcMgr::stopListening() +{ + osl::MutexGuard aGuard(GetLinguMutex()); + + if (xMB.is()) + { + try + { + uno::Reference xListener(this); + xMB->removeModifyListener(xListener); + } + catch (const uno::Exception&) + { + } + + xMB.clear(); + } +} + +void LngSvcMgr::disposing(const lang::EventObject&) + throw (uno::RuntimeException) +{ + stopListening(); +} LngSvcMgr::~LngSvcMgr() { + stopListening(); + // memory for pSpellDsp, pHyphDsp, pThesDsp, pListenerHelper // will be freed in the destructor of the respective Reference's // xSpellDsp, xGrammarDsp, xHyphDsp, xThesDsp @@ -498,6 +584,252 @@ delete pAvailThesSvcs; } +namespace +{ + using lang::Locale; + using uno::Any; + using uno::Sequence; + + sal_Bool lcl_FindEntry( const OUString &rEntry, const Sequence< OUString > &rCfgSvcs ) + { + sal_Int32 nRes = -1; + sal_Int32 nEntries = rCfgSvcs.getLength(); + const OUString *pEntry = rCfgSvcs.getConstArray(); + for (sal_Int32 i = 0; i < nEntries && nRes == -1; ++i) + { + if (rEntry == pEntry[i]) + nRes = i; + } + return nRes != -1; + } + + Sequence< OUString > lcl_GetLastFoundSvcs( + SvtLinguConfig &rCfg, + const OUString &rLastFoundList , + const Locale &rAvailLocale ) + { + Sequence< OUString > aRes; + + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + LocaleToLanguage( rAvailLocale ) ) ); + + Sequence< OUString > aNodeNames( rCfg.GetNodeNames(rLastFoundList) ); + sal_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 (aValues.getLength()) + { + OSL_ENSURE( aValues.getLength() == 1, "unexpected length of sequence" ); + Sequence< OUString > aSvcImplNames; + if (aValues.getConstArray()[0] >>= aSvcImplNames) + aRes = aSvcImplNames; + else + { + OSL_FAIL( "type mismatch" ); + } + } + } + + return aRes; + } + + Sequence< OUString > lcl_RemoveMissingEntries( + const Sequence< OUString > &rCfgSvcs, + const Sequence< OUString > &rAvailSvcs ) + { + Sequence< OUString > aRes( rCfgSvcs.getLength() ); + OUString *pRes = aRes.getArray(); + sal_Int32 nCnt = 0; + + sal_Int32 nEntries = rCfgSvcs.getLength(); + const OUString *pEntry = rCfgSvcs.getConstArray(); + for (sal_Int32 i = 0; i < nEntries; ++i) + { + if (!pEntry[i].isEmpty() && lcl_FindEntry( pEntry[i], rAvailSvcs )) + pRes[ nCnt++ ] = pEntry[i]; + } + + aRes.realloc( nCnt ); + return aRes; + } + + Sequence< OUString > lcl_GetNewEntries( + const Sequence< OUString > &rLastFoundSvcs, + const Sequence< OUString > &rAvailSvcs ) + { + sal_Int32 nLen = rAvailSvcs.getLength(); + Sequence< OUString > aRes( nLen ); + OUString *pRes = aRes.getArray(); + sal_Int32 nCnt = 0; + + const OUString *pEntry = rAvailSvcs.getConstArray(); + for (sal_Int32 i = 0; i < nLen; ++i) + { + if (!pEntry[i].isEmpty() && !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(); + sal_Int32 nCnt = 0; + + for (sal_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; + + sal_Int32 nLen = rSeq.getLength(); + const OUString *pEntry = rSeq.getConstArray(); + for (sal_Int32 i = 0; i < nLen; ++i) + { + if (!pEntry[i].isEmpty() && !lcl_FindEntry( pEntry[i], aRes )) + pRes[ nCnt++ ] = pEntry[i]; + } + } + + aRes.realloc( nCnt ); + return aRes; + } +} + +void LngSvcMgr::UpdateAll() +{ + using beans::PropertyValue; + using lang::Locale; + using uno::Sequence; + + typedef OUString OUstring_t; + typedef Sequence< OUString > Sequence_OUString_t; + typedef std::map< OUstring_t, Sequence_OUString_t > list_entry_map_t; + + 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( ::rtl::OUString::createFromAscii( apServices[k] ) ); + OUString aActiveList( ::rtl::OUString::createFromAscii( apCurLists[k] ) ); + OUString aLastFoundList( ::rtl::OUString::createFromAscii( apLastFoundLists[k] ) ); + sal_Int32 i; + + // + // remove configured but not available language/services entries + // + Sequence< OUString > aNodeNames( aCfg.GetNodeNames( aActiveList ) ); // list of configured locales + sal_Int32 nNodeNames = aNodeNames.getLength(); + const OUString *pNodeName = aNodeNames.getConstArray(); + for (i = 0; i < nNodeNames; ++i) + { + Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(pNodeName[i]) ) ); + Sequence< OUString > aCfgSvcs( getConfiguredServices( aService, aLocale )); + Sequence< OUString > aAvailSvcs( getAvailableServices( aService, aLocale )); + + aCfgSvcs = lcl_RemoveMissingEntries( aCfgSvcs, aAvailSvcs ); + + aCurSvcs[k][ pNodeName[i] ] = aCfgSvcs; + } + + // + // add new available language/service entries + // and + // set last found services to currently available ones + // + Sequence< Locale > aAvailLocales( getAvailableLocales(aService) ); + sal_Int32 nAvailLocales = aAvailLocales.getLength(); + const Locale *pAvailLocale = aAvailLocales.getConstArray(); + for (i = 0; i < nAvailLocales; ++i) + { + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + LocaleToLanguage( pAvailLocale[i] ) ) ); + + Sequence< OUString > aAvailSvcs( getAvailableServices( aService, pAvailLocale[i] )); + + aLastFoundSvcs[k][ aCfgLocaleStr ] = aAvailSvcs; + + Sequence< OUString > aLastSvcs( + lcl_GetLastFoundSvcs( aCfg, aLastFoundList , pAvailLocale[i] )); + Sequence< OUString > aNewSvcs = + lcl_GetNewEntries( aLastSvcs, aAvailSvcs ); + + Sequence< OUString > aCfgSvcs( aCurSvcs[k][ aCfgLocaleStr ] ); + + // merge services list (previously configured to be listed first). + aCfgSvcs = lcl_MergeSeq( aCfgSvcs, aNewSvcs ); + + aCurSvcs[k][ aCfgLocaleStr ] = aCfgSvcs; + } + } + + // + // 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( ::rtl::OUString::createFromAscii(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; + + pNewValue->Name = aCfgEntryName; + pNewValue->Value <<= (*aIt).second; + ++pNewValue; + ++aIt; + } + OSL_ENSURE( pNewValue - aNewValues.getArray() == nVals, + "possible mismatch of sequence size and property number" ); + + { + // add new or replace existing entries. + sal_Bool bRes = aCfg.ReplaceSetProperties( aSubNodeName, aNewValues ); + if (!bRes) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "failed to set new configuration values" ); +#endif + } + } + } + } + + //The new settings in the configuration get applied ! because we are + //listening to the configuration for changes of the relevant ! properties + //and Notify applies the new settings. +} void LngSvcMgr::Notify( const uno::Sequence< OUString > &rPropertyNames ) { @@ -1263,32 +1595,21 @@ if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER )) { - // don't used cached data here (force re-evaluation in order to have downloaded dictionaries - // already found without the need to restart the office - delete pAvailSpellSvcs; pAvailSpellSvcs = 0; GetAvailableSpellSvcs_Impl(); pInfoArray = pAvailSpellSvcs; } else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER )) { -// disable force re-loading of the cache - re-start needed for new grammer checkers: fdo#35270 -// delete pAvailGrammarSvcs; pAvailGrammarSvcs = 0; GetAvailableGrammarSvcs_Impl(); pInfoArray = pAvailGrammarSvcs; } else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR )) { - // don't used cached data here (force re-evaluation in order to have downloaded dictionaries - // already found without the need to restart the office - delete pAvailHyphSvcs; pAvailHyphSvcs = 0; GetAvailableHyphSvcs_Impl(); pInfoArray = pAvailHyphSvcs; } else if (0 == rServiceName.compareToAscii( SN_THESAURUS )) { - // don't used cached data here (force re-evaluation in order to have downloaded dictionaries - // already found without the need to restart the office - delete pAvailThesSvcs; pAvailThesSvcs = 0; GetAvailableThesSvcs_Impl(); pInfoArray = pAvailThesSvcs; } diff -ru libreoffice-3.5.5.3.orig/linguistic/source/lngsvcmgr.hxx libreoffice-3.5.5.3/linguistic/source/lngsvcmgr.hxx --- libreoffice-3.5.5.3.orig/linguistic/source/lngsvcmgr.hxx 2012-07-13 12:23:35.598866391 +0100 +++ libreoffice-3.5.5.3/linguistic/source/lngsvcmgr.hxx 2012-07-16 08:49:27.833227231 +0100 @@ -30,7 +30,7 @@ #define _LINGUISTIC_LNGSVCMGR_HXX_ #include // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type -#include // helper for implementations +#include // helper for implementations #include //OMultiTypeInterfaceContainerHelper @@ -39,8 +39,10 @@ #include #include #include +#include +#include #include - +#include #include #include "linguistic/misc.hxx" @@ -65,12 +67,13 @@ class LngSvcMgr : - public cppu::WeakImplHelper4 + public cppu::WeakImplHelper5 < com::sun::star::linguistic2::XLinguServiceManager, com::sun::star::linguistic2::XAvailableLocales, com::sun::star::lang::XComponent, - com::sun::star::lang::XServiceInfo + com::sun::star::lang::XServiceInfo, + com::sun::star::util::XModifyListener >, private utl::ConfigItem { @@ -90,6 +93,12 @@ com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener > xListenerHelper; + com::sun::star::uno::Reference< + ::com::sun::star::util::XModifyBroadcaster> xMB; + + Timer aUpdateTimer; + + com::sun::star::uno::Sequence< com::sun::star::lang::Locale > aAvailSpellLocales; com::sun::star::uno::Sequence< @@ -140,6 +149,10 @@ virtual void Notify( const com::sun::star::uno::Sequence< rtl::OUString > &rPropertyNames ); virtual void Commit(); + void UpdateAll(); + void stopListening(); + DECL_LINK( updateAndBroadcast, void* ); + public: LngSvcMgr(); virtual ~LngSvcMgr(); @@ -167,6 +180,11 @@ virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& rSource ) throw(::com::sun::star::uno::RuntimeException); + + // XModifyListener + virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& rEvent ) throw(::com::sun::star::uno::RuntimeException); static inline ::rtl::OUString getImplementationName_Static(); static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static() throw();