diff options
Diffstat (limited to 'svx/source/smarttags/SmartTagMgr.cxx')
-rw-r--r-- | svx/source/smarttags/SmartTagMgr.cxx | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/svx/source/smarttags/SmartTagMgr.cxx b/svx/source/smarttags/SmartTagMgr.cxx new file mode 100644 index 0000000000..37b9bc9352 --- /dev/null +++ b/svx/source/smarttags/SmartTagMgr.cxx @@ -0,0 +1,528 @@ +/* -*- 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 <svx/SmartTagMgr.hxx> + +#include <utility> +#include <vcl/svapp.hxx> +#include <com/sun/star/smarttags/XSmartTagRecognizer.hpp> +#include <com/sun/star/smarttags/XRangeBasedSmartTagRecognizer.hpp> +#include <com/sun/star/smarttags/XSmartTagAction.hpp> +#include <com/sun/star/deployment/ExtensionManager.hpp> +#include <com/sun/star/smarttags/SmartTagRecognizerMode.hpp> +#include <com/sun/star/i18n/BreakIterator.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <rtl/ustring.hxx> + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::i18n; + + +SmartTagMgr::SmartTagMgr( OUString aApplicationName ) + : maApplicationName(std::move( aApplicationName )), + 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<smarttags::XSmartTagRecognizer>& 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<deployment::XExtensionManager> 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<util::XChangesNotifier> 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: */ |