/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ // SMARTTAGS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; using namespace com::sun::star::uno; using namespace com::sun::star::i18n; SmartTagMgr::SmartTagMgr( const OUString& rApplicationName ) : maApplicationName( rApplicationName ), mxContext( ::comphelper::getProcessComponentContext() ), mbLabelTextWithSmartTags(true) { } SmartTagMgr::~SmartTagMgr() { } void SmartTagMgr::Init( std::u16string_view rConfigurationGroupName ) { PrepareConfiguration( rConfigurationGroupName ); ReadConfiguration( true, true ); RegisterListener(); LoadLibraries(); } /** Dispatches the recognize call to all installed smart tag recognizers */ void SmartTagMgr::RecognizeString( const OUString& rText, const Reference< text::XTextMarkup >& xMarkup, const Reference< frame::XController >& xController, const lang::Locale& rLocale, sal_uInt32 nStart, sal_uInt32 nLen ) const { for (const Reference < smarttags::XSmartTagRecognizer >& xRecognizer : maRecognizerList) { // if all smart tag types supported by this recognizer have been // disabled, we do not have to call the recognizer: bool bCallRecognizer = false; const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount(); for ( sal_uInt32 j = 0; j < nSmartTagCount && !bCallRecognizer; ++j ) { const OUString aSmartTagName = xRecognizer->getSmartTagName(j); if ( IsSmartTagTypeEnabled( aSmartTagName ) ) bCallRecognizer = true; } if ( bCallRecognizer ) { // get the break iterator if ( !mxBreakIter.is() ) { mxBreakIter.set( BreakIterator::create(mxContext) ); } xRecognizer->recognize( rText, nStart, nLen, smarttags::SmartTagRecognizerMode_PARAGRAPH, rLocale, xMarkup, maApplicationName, xController, mxBreakIter ); } } } void SmartTagMgr::RecognizeTextRange(const Reference< text::XTextRange>& xRange, const Reference< text::XTextMarkup >& xMarkup, const Reference< frame::XController >& xController) const { for (const Reference& xRecognizer : maRecognizerList) { Reference< smarttags::XRangeBasedSmartTagRecognizer > xRangeBasedRecognizer( xRecognizer, UNO_QUERY); if (!xRangeBasedRecognizer.is()) continue; // if all smart tag types supported by this recognizer have been // disabled, we do not have to call the recognizer: bool bCallRecognizer = false; const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount(); for ( sal_uInt32 j = 0; j < nSmartTagCount && !bCallRecognizer; ++j ) { const OUString aSmartTagName = xRecognizer->getSmartTagName(j); if ( IsSmartTagTypeEnabled( aSmartTagName ) ) bCallRecognizer = true; } if ( bCallRecognizer ) { xRangeBasedRecognizer->recognizeTextRange( xRange, smarttags::SmartTagRecognizerMode_PARAGRAPH, xMarkup, maApplicationName, xController); } } } void SmartTagMgr::GetActionSequences( std::vector< OUString >& rSmartTagTypes, Sequence < Sequence< Reference< smarttags::XSmartTagAction > > >& rActionComponentsSequence, Sequence < Sequence< sal_Int32 > >& rActionIndicesSequence ) const { rActionComponentsSequence.realloc( rSmartTagTypes.size() ); auto pActionComponentsSequence = rActionComponentsSequence.getArray(); rActionIndicesSequence.realloc( rSmartTagTypes.size() ); auto pActionIndicesSequence = rActionIndicesSequence.getArray(); for ( size_t j = 0; j < rSmartTagTypes.size(); ++j ) { const OUString& rSmartTagType = rSmartTagTypes[j]; const sal_Int32 nNumberOfActionRefs = maSmartTagMap.count( rSmartTagType ); Sequence< Reference< smarttags::XSmartTagAction > > aActions( nNumberOfActionRefs ); auto aActionsRange = asNonConstRange(aActions); Sequence< sal_Int32 > aIndices( nNumberOfActionRefs ); auto aIndicesRange = asNonConstRange(aIndices); sal_uInt16 i = 0; auto iters = maSmartTagMap.equal_range( rSmartTagType ); for ( auto aActionsIter = iters.first; aActionsIter != iters.second; ++aActionsIter ) { aActionsRange[ i ] = (*aActionsIter).second.mxSmartTagAction; aIndicesRange[ i++ ] = (*aActionsIter).second.mnSmartTagIndex; } pActionComponentsSequence[ j ] = aActions; pActionIndicesSequence[ j ] = aIndices; } } /** Returns the caption for a smart tag type. */ OUString SmartTagMgr::GetSmartTagCaption( const OUString& rSmartTagType, const css::lang::Locale& rLocale ) const { OUString aRet; auto aLower = maSmartTagMap.find( rSmartTagType ); if ( aLower != maSmartTagMap.end() ) { const ActionReference& rActionRef = (*aLower).second; Reference< smarttags::XSmartTagAction > xAction = rActionRef.mxSmartTagAction; if ( xAction.is() ) { const sal_Int32 nSmartTagIndex = rActionRef.mnSmartTagIndex; aRet = xAction->getSmartTagCaption( nSmartTagIndex, rLocale ); } } return aRet; } /** Returns true if the given smart tag type is enabled. */ bool SmartTagMgr::IsSmartTagTypeEnabled( const OUString& rSmartTagType ) const { return maDisabledSmartTagTypes.end() == maDisabledSmartTagTypes.find( rSmartTagType ); } /** Writes currently disabled smart tag types to configuration. */ void SmartTagMgr::WriteConfiguration( const bool* pIsLabelTextWithSmartTags, const std::vector< OUString >* pDisabledTypes ) const { if ( !mxConfigurationSettings.is() ) return; bool bCommit = false; if ( pIsLabelTextWithSmartTags ) { const Any aEnabled( *pIsLabelTextWithSmartTags ); try { mxConfigurationSettings->setPropertyValue( "RecognizeSmartTags", aEnabled ); bCommit = true; } catch ( css::uno::Exception& ) { } } if ( pDisabledTypes ) { Sequence< OUString > aTypes = comphelper::containerToSequence(*pDisabledTypes); const Any aNewTypes( aTypes ); try { mxConfigurationSettings->setPropertyValue( "ExcludedSmartTagTypes", aNewTypes ); bCommit = true; } catch ( css::uno::Exception& ) { } } if ( bCommit ) { try { Reference< util::XChangesBatch >( mxConfigurationSettings, UNO_QUERY_THROW )->commitChanges(); } catch ( css::uno::Exception& ) { } } } // css::util::XModifyListener void SmartTagMgr::modified( const lang::EventObject& ) { SolarMutexGuard aGuard; maRecognizerList.clear(); maActionList.clear(); maSmartTagMap.clear(); LoadLibraries(); } // css::lang::XEventListener void SmartTagMgr::disposing( const lang::EventObject& rEvent ) { SolarMutexGuard aGuard; uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY ); uno::Reference< util::XModifyBroadcaster > xMB(xModel, uno::UNO_QUERY); uno::Reference< util::XChangesNotifier > xCN(xModel, uno::UNO_QUERY); try { if( xMB.is() ) { uno::Reference< util::XModifyListener > xListener( this ); xMB->removeModifyListener( xListener ); } else if ( xCN.is() ) { uno::Reference< util::XChangesListener > xListener( this ); xCN->removeChangesListener( xListener ); } } catch(Exception& ) { } } // css::util::XChangesListener void SmartTagMgr::changesOccurred( const util::ChangesEvent& rEvent ) { SolarMutexGuard aGuard; bool bExcludedTypes = false; bool bRecognize = false; for( const util::ElementChange& rElementChange : rEvent.Changes) { OUString sTemp; rElementChange.Accessor >>= sTemp; if ( sTemp == "ExcludedSmartTagTypes" ) bExcludedTypes = true; else if ( sTemp == "RecognizeSmartTags" ) bRecognize = true; } ReadConfiguration( bExcludedTypes, bRecognize ); } void SmartTagMgr::LoadLibraries() { Reference< container::XContentEnumerationAccess > rContent( mxContext->getServiceManager(), UNO_QUERY_THROW ); // load recognizers: No recognizers -> nothing to do. Reference < container::XEnumeration > rEnum = rContent->createContentEnumeration( "com.sun.star.smarttags.SmartTagRecognizer"); if ( !rEnum.is() || !rEnum->hasMoreElements() ) return; // iterate over all implementations of the smart tag recognizer service: while( rEnum->hasMoreElements()) { const Any a = rEnum->nextElement(); Reference< lang::XSingleComponentFactory > xSCF; Reference< lang::XServiceInfo > xsInfo; if (a >>= xsInfo) xSCF.set(xsInfo, UNO_QUERY); else continue; Reference< smarttags::XSmartTagRecognizer > xLib ( xSCF-> createInstanceWithContext(mxContext), UNO_QUERY ); if (!xLib.is()) continue; xLib->initialize( Sequence< Any >() ); maRecognizerList.push_back(xLib); } // load actions: No actions -> nothing to do. rEnum = rContent->createContentEnumeration( "com.sun.star.smarttags.SmartTagAction"); if ( !rEnum.is() ) return; // iterate over all implementations of the smart tag action service: while( rEnum->hasMoreElements()) { const Any a = rEnum->nextElement(); Reference< lang::XServiceInfo > xsInfo; Reference< lang::XSingleComponentFactory > xSCF; if (a >>= xsInfo) xSCF.set(xsInfo, UNO_QUERY); else continue; Reference< smarttags::XSmartTagAction > xLib ( xSCF-> createInstanceWithContext(mxContext), UNO_QUERY ); if (!xLib.is()) continue; xLib->initialize( Sequence< Any >() ); maActionList.push_back(xLib); } AssociateActionsWithRecognizers(); } void SmartTagMgr::PrepareConfiguration( std::u16string_view rConfigurationGroupName ) { Any aAny( OUString::Concat("/org.openoffice.Office.Common/SmartTags/") + rConfigurationGroupName ); beans::PropertyValue aPathArgument; aPathArgument.Name = "nodepath"; aPathArgument.Value = aAny; Sequence< Any > aArguments{ Any(aPathArgument) }; Reference< lang::XMultiServiceFactory > xConfProv = configuration::theDefaultProvider::get( mxContext ); // try to get read-write access to configuration: Reference< XInterface > xConfigurationAccess; try { xConfigurationAccess = xConfProv->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", aArguments ); } catch ( uno::Exception& ) { } // fallback: try read-only access to configuration: if ( !xConfigurationAccess.is() ) { try { xConfigurationAccess = xConfProv->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", aArguments ); } catch ( uno::Exception& ) { } } if ( xConfigurationAccess.is() ) { mxConfigurationSettings.set( xConfigurationAccess, UNO_QUERY ); } } void SmartTagMgr::ReadConfiguration( bool bExcludedTypes, bool bRecognize ) { if ( !mxConfigurationSettings.is() ) return; if ( bExcludedTypes ) { maDisabledSmartTagTypes.clear(); Any aAny = mxConfigurationSettings->getPropertyValue( "ExcludedSmartTagTypes" ); Sequence< OUString > aValues; aAny >>= aValues; for ( const auto& rValue : std::as_const(aValues) ) maDisabledSmartTagTypes.insert( rValue ); } if ( bRecognize ) { Any aAny = mxConfigurationSettings->getPropertyValue( "RecognizeSmartTags" ); bool bValue = true; aAny >>= bValue; mbLabelTextWithSmartTags = bValue; } } void SmartTagMgr::RegisterListener() { // register as listener at package manager try { Reference xExtensionManager( deployment::ExtensionManager::get( mxContext ) ); Reference< util::XModifyBroadcaster > xMB ( xExtensionManager, UNO_QUERY_THROW ); Reference< util::XModifyListener > xListener( this ); xMB->addModifyListener( xListener ); } catch ( uno::Exception& ) { } // register as listener at configuration try { Reference xCN( mxConfigurationSettings, UNO_QUERY_THROW ); Reference< util::XChangesListener > xListener( this ); xCN->addChangesListener( xListener ); } catch ( uno::Exception& ) { } } typedef std::pair < const OUString, ActionReference > SmartTagMapElement; /** Sets up a map that maps smart tag type names to actions references. */ void SmartTagMgr::AssociateActionsWithRecognizers() { const sal_uInt32 nActionLibCount = maActionList.size(); const sal_uInt32 nRecognizerCount = maRecognizerList.size(); for ( sal_uInt32 i = 0; i < nRecognizerCount; ++i ) { Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i]; const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount(); for ( sal_uInt32 j = 0; j < nSmartTagCount; ++j ) { const OUString aSmartTagName = xRecognizer->getSmartTagName(j); // check if smart tag type has already been processed: if ( maSmartTagMap.find( aSmartTagName ) != maSmartTagMap.end() ) continue; bool bFound = false; for ( sal_uInt32 k = 0; k < nActionLibCount; ++k ) { Reference< smarttags::XSmartTagAction > xActionLib = maActionList[k]; const sal_uInt32 nSmartTagCountInActionLib = xActionLib->getSmartTagCount(); for ( sal_uInt32 l = 0; l < nSmartTagCountInActionLib; ++l ) { const OUString aSmartTagNameInActionLib = xActionLib->getSmartTagName(l); if ( aSmartTagName == aSmartTagNameInActionLib ) { // found actions and recognizer for same smarttag ActionReference aActionRef( xActionLib, l ); // add recognizer/action pair to map maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef )); bFound = true; } } } if ( !bFound ) { // insert 'empty' action reference if there is no action associated with // the current smart tag type: Reference< smarttags::XSmartTagAction > xActionLib; ActionReference aActionRef( xActionLib, 0 ); // add recognizer/action pair to map maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef )); } } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */