| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // SMARTTAGS |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svx.hxx" |
| #include <svx/SmartTagMgr.hxx> |
| |
| #include <vos/mutex.hxx> |
| #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/text/XTextMarkup.hpp> |
| #include <com/sun/star/smarttags/SmartTagRecognizerMode.hpp> |
| #include <com/sun/star/i18n/XBreakIterator.hpp> |
| #include <com/sun/star/lang/Locale.hpp> |
| #include <com/sun/star/lang/EventObject.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/container/XContentEnumerationAccess.hpp> |
| #include <com/sun/star/container/XNameContainer.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 <rtl/ustring.hxx> |
| #include <tools/string.hxx> |
| |
| #include <com/sun/star/text/XTextRange.hpp> |
| |
| using namespace com::sun::star; |
| using namespace com::sun::star::uno; |
| |
| #define C2U(cChar) rtl::OUString::createFromAscii(cChar) |
| |
| |
| SmartTagMgr::SmartTagMgr( const rtl::OUString& rApplicationName ) |
| : maApplicationName( rApplicationName ), |
| maRecognizerList(), |
| maActionList(), |
| maDisabledSmartTagTypes(), |
| maSmartTagMap(), |
| mxMSF( ::comphelper::getProcessServiceFactory() ), |
| mbLabelTextWithSmartTags(true) |
| { |
| } |
| |
| SmartTagMgr::~SmartTagMgr() |
| { |
| } |
| |
| void SmartTagMgr::Init( const rtl::OUString& rConfigurationGroupName ) |
| { |
| // get component context to pass to components: |
| if ( mxMSF.is() ) |
| { |
| Reference< beans::XPropertySet > xPropSet = Reference< beans::XPropertySet>( mxMSF, UNO_QUERY); |
| const Any aAny = xPropSet->getPropertyValue( C2U("DefaultContext")); |
| aAny >>= mxContext; |
| |
| if ( mxContext.is() ) |
| { |
| PrepareConfiguration( rConfigurationGroupName ); |
| ReadConfiguration( true, true ); |
| RegisterListener(); |
| LoadLibraries(); |
| } |
| } |
| } |
| void SmartTagMgr::CreateBreakIterator() const |
| { |
| if ( !mxBreakIter.is() && mxMSF.is() && mxContext.is() ) |
| { |
| // get the break iterator |
| mxBreakIter.set(mxMSF->createInstance( C2U( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY); |
| } |
| } |
| |
| /** Dispatches the recognize call to all installed smart tag recognizers |
| */ |
| void SmartTagMgr::RecognizeString( const rtl::OUString& rText, |
| const Reference< text::XTextMarkup > xMarkup, |
| const Reference< frame::XController > xController, |
| const lang::Locale& rLocale, |
| sal_uInt32 nStart, sal_uInt32 nLen ) const |
| { |
| for ( sal_uInt32 i = 0; i < maRecognizerList.size(); i++ ) |
| { |
| Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i]; |
| |
| // 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 rtl::OUString aSmartTagName = xRecognizer->getSmartTagName(j); |
| if ( IsSmartTagTypeEnabled( aSmartTagName ) ) |
| bCallRecognizer = true; |
| } |
| |
| if ( bCallRecognizer ) |
| { |
| CreateBreakIterator(); |
| maRecognizerList[i]->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 ( sal_uInt32 i = 0; i < maRecognizerList.size(); i++ ) |
| { |
| Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i]; |
| |
| Reference< smarttags::XRangeBasedSmartTagRecognizer > xRangeBasedRecognizer = Reference< smarttags::XRangeBasedSmartTagRecognizer >( 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 rtl::OUString aSmartTagName = xRecognizer->getSmartTagName(j); |
| if ( IsSmartTagTypeEnabled( aSmartTagName ) ) |
| bCallRecognizer = true; |
| } |
| |
| if ( bCallRecognizer ) |
| { |
| xRangeBasedRecognizer->recognizeTextRange( xRange, |
| smarttags::SmartTagRecognizerMode_PARAGRAPH, |
| xMarkup, maApplicationName, xController); |
| } |
| } |
| |
| } |
| |
| |
| typedef std::multimap < rtl::OUString, ActionReference >::const_iterator SmartTagMapIter; |
| |
| void SmartTagMgr::GetActionSequences( Sequence < rtl::OUString >& rSmartTagTypes, |
| Sequence < Sequence< Reference< smarttags::XSmartTagAction > > >& rActionComponentsSequence, |
| Sequence < Sequence< sal_Int32 > >& rActionIndicesSequence ) const |
| { |
| rActionComponentsSequence.realloc( rSmartTagTypes.getLength() ); |
| rActionIndicesSequence.realloc( rSmartTagTypes.getLength() ); |
| |
| for ( sal_uInt16 j = 0; j < rSmartTagTypes.getLength(); ++j ) |
| { |
| const rtl::OUString& rSmartTagType = rSmartTagTypes[j]; |
| |
| const sal_Int32 nNumberOfActionRefs = maSmartTagMap.count( rSmartTagType ); |
| |
| Sequence< Reference< smarttags::XSmartTagAction > > aActions( nNumberOfActionRefs ); |
| Sequence< sal_Int32 > aIndices( nNumberOfActionRefs ); |
| |
| sal_uInt16 i = 0; |
| SmartTagMapIter aActionsIter; |
| SmartTagMapIter aEnd = maSmartTagMap.upper_bound( rSmartTagType ); |
| |
| for ( aActionsIter = maSmartTagMap.lower_bound( rSmartTagType ); aActionsIter != aEnd; ++aActionsIter ) |
| { |
| aActions[ i ] = (*aActionsIter).second.mxSmartTagAction; |
| aIndices[ i++ ] = (*aActionsIter).second.mnSmartTagIndex; |
| } |
| |
| rActionComponentsSequence[ j ] = aActions; |
| rActionIndicesSequence[ j ] = aIndices; |
| } |
| } |
| |
| /** Returns the caption for a smart tag type. |
| */ |
| rtl::OUString SmartTagMgr::GetSmartTagCaption( const rtl::OUString& rSmartTagType, const com::sun::star::lang::Locale& rLocale ) const |
| { |
| rtl::OUString aRet; |
| |
| SmartTagMapIter aLower = maSmartTagMap.lower_bound( 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 rtl::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< rtl::OUString >* pDisabledTypes ) const |
| { |
| if ( mxConfigurationSettings.is() ) |
| { |
| bool bCommit = false; |
| |
| if ( pIsLabelTextWithSmartTags ) |
| { |
| const Any aEnabled = makeAny( *pIsLabelTextWithSmartTags ); |
| |
| try |
| { |
| mxConfigurationSettings->setPropertyValue( C2U("RecognizeSmartTags"), aEnabled ); |
| bCommit = true; |
| } |
| catch ( ::com::sun::star::uno::Exception& ) |
| { |
| } |
| } |
| |
| if ( pDisabledTypes ) |
| { |
| const sal_Int32 nNumberOfDisabledSmartTagTypes = pDisabledTypes->size(); |
| Sequence< rtl::OUString > aTypes( nNumberOfDisabledSmartTagTypes ); |
| |
| std::vector< rtl::OUString >::const_iterator aIter; |
| sal_Int32 nCount = 0; |
| for ( aIter = pDisabledTypes->begin(); aIter != pDisabledTypes->end(); ++aIter ) |
| aTypes[ nCount++ ] = *aIter; |
| |
| const Any aNewTypes = makeAny( aTypes ); |
| |
| try |
| { |
| mxConfigurationSettings->setPropertyValue( C2U("ExcludedSmartTagTypes"), aNewTypes ); |
| bCommit = true; |
| } |
| catch ( ::com::sun::star::uno::Exception& ) |
| { |
| } |
| } |
| |
| if ( bCommit ) |
| { |
| try |
| { |
| Reference< util::XChangesBatch >( mxConfigurationSettings, UNO_QUERY_THROW )->commitChanges(); |
| } |
| catch ( ::com::sun::star::uno::Exception& ) |
| { |
| } |
| } |
| } |
| } |
| |
| // ::com::sun::star::util::XModifyListener |
| void SmartTagMgr::modified( const lang::EventObject& ) throw( RuntimeException ) |
| { |
| vos::OGuard aGuard(Application::GetSolarMutex()); |
| |
| maRecognizerList.clear(); |
| maActionList.clear(); |
| maSmartTagMap.clear(); |
| |
| LoadLibraries(); |
| } |
| |
| // ::com::sun::star::lang::XEventListener |
| void SmartTagMgr::disposing( const lang::EventObject& rEvent ) throw( RuntimeException ) |
| { |
| vos::OGuard aGuard(Application::GetSolarMutex()); |
| |
| 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& ) |
| { |
| } |
| } |
| |
| // ::com::sun::star::util::XChangesListener |
| void SmartTagMgr::changesOccurred( const util::ChangesEvent& rEvent ) throw( RuntimeException) |
| { |
| vos::OGuard aGuard(Application::GetSolarMutex()); |
| |
| const util::ElementChange* pElementChanges = rEvent.Changes.getConstArray(); |
| const sal_Int32 nNumberOfChanges = rEvent.Changes.getLength(); |
| bool bExcludedTypes = false; |
| bool bRecognize = false; |
| |
| for( sal_Int32 i = 0; i < nNumberOfChanges; ++i) |
| { |
| rtl::OUString sTemp; |
| pElementChanges[i].Accessor >>= sTemp; |
| |
| if ( sTemp == C2U( "ExcludedSmartTagTypes" ) ) |
| bExcludedTypes = true; |
| else if ( sTemp == C2U( "RecognizeSmartTags" ) ) |
| bRecognize = true; |
| } |
| |
| ReadConfiguration( bExcludedTypes, bRecognize ); |
| } |
| |
| //------------- PRIVATE ----------------------------------------------- |
| |
| /** |
| */ |
| void SmartTagMgr::LoadLibraries() |
| { |
| Reference< container::XContentEnumerationAccess > rContent( mxMSF , UNO_QUERY ); |
| if ( !rContent.is() ) |
| return; |
| |
| // load recognizers: No recognizers -> nothing to do. |
| Reference < container::XEnumeration > rEnum = rContent->createContentEnumeration( C2U("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 = Reference< lang::XSingleComponentFactory >(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( C2U("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 = Reference< lang::XSingleComponentFactory >(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( const rtl::OUString& rConfigurationGroupName ) |
| { |
| Any aAny = makeAny( C2U( "/org.openoffice.Office.Common/SmartTags/" ) + rConfigurationGroupName ); |
| beans::PropertyValue aPathArgument; |
| aPathArgument.Name = C2U( "nodepath" ); |
| aPathArgument.Value = aAny; |
| Sequence< Any > aArguments( 1 ); |
| aArguments[ 0 ] <<= aPathArgument; |
| Reference< lang::XMultiServiceFactory > xConfProv( mxMSF->createInstance(C2U ("com.sun.star.configuration.ConfigurationProvider")), UNO_QUERY ); |
| |
| if ( !xConfProv.is() ) |
| return; |
| |
| // try to get read-write access to configuration: |
| Reference< XInterface > xConfigurationAccess; |
| try |
| { |
| xConfigurationAccess = xConfProv->createInstanceWithArguments( |
| C2U("com.sun.star.configuration.ConfigurationUpdateAccess" ), aArguments ); |
| } |
| catch ( uno::Exception& ) |
| { |
| } |
| |
| // fallback: try read-only access to configuration: |
| if ( !xConfigurationAccess.is() ) |
| { |
| try |
| { |
| xConfigurationAccess = xConfProv->createInstanceWithArguments( |
| C2U("com.sun.star.configuration.ConfigurationAccess" ), aArguments ); |
| } |
| catch ( uno::Exception& ) |
| { |
| } |
| } |
| |
| if ( xConfigurationAccess.is() ) |
| { |
| mxConfigurationSettings = Reference< beans::XPropertySet >( xConfigurationAccess, UNO_QUERY ); |
| } |
| } |
| |
| |
| void SmartTagMgr::ReadConfiguration( bool bExcludedTypes, bool bRecognize ) |
| { |
| if ( mxConfigurationSettings.is() ) |
| { |
| if ( bExcludedTypes ) |
| { |
| maDisabledSmartTagTypes.clear(); |
| |
| Any aAny = mxConfigurationSettings->getPropertyValue( C2U("ExcludedSmartTagTypes") ); |
| Sequence< rtl::OUString > aValues; |
| aAny >>= aValues; |
| |
| const sal_Int32 nValues = aValues.getLength(); |
| |
| for ( sal_Int32 nI = 0; nI < nValues; ++nI ) |
| maDisabledSmartTagTypes.insert( aValues[nI] ); |
| } |
| |
| if ( bRecognize ) |
| { |
| Any aAny = mxConfigurationSettings->getPropertyValue( C2U("RecognizeSmartTags") ); |
| sal_Bool bValue = sal_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 rtl::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 rtl::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 rtl::OUString aSmartTagNameInActionLib = xActionLib->getSmartTagName(l); |
| if ( aSmartTagName.equals( 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 )); |
| } |
| } |
| } |
| } |
| |