1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // SMARTTAGS
25
26 // MARKER(update_precomp.py): autogen include statement, do not remove
27 #include "precompiled_svx.hxx"
28 #include <svx/SmartTagMgr.hxx>
29
30 #include <vos/mutex.hxx>
31 #include <vcl/svapp.hxx>
32 #include <com/sun/star/smarttags/XSmartTagRecognizer.hpp>
33 #include <com/sun/star/smarttags/XRangeBasedSmartTagRecognizer.hpp>
34 #include <com/sun/star/smarttags/XSmartTagAction.hpp>
35 #include <com/sun/star/deployment/ExtensionManager.hpp>
36 #include <com/sun/star/text/XTextMarkup.hpp>
37 #include <com/sun/star/smarttags/SmartTagRecognizerMode.hpp>
38 #include <com/sun/star/i18n/XBreakIterator.hpp>
39 #include <com/sun/star/lang/Locale.hpp>
40 #include <com/sun/star/lang/EventObject.hpp>
41 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
43 #include <com/sun/star/lang/XServiceInfo.hpp>
44 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
45 #include <com/sun/star/container/XNameContainer.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/beans/PropertyValue.hpp>
48 #include <com/sun/star/util/XChangesBatch.hpp>
49 #include <com/sun/star/util/XChangesNotifier.hpp>
50 #include <comphelper/processfactory.hxx>
51 #include <rtl/ustring.hxx>
52 #include <tools/string.hxx>
53
54 #include <com/sun/star/text/XTextRange.hpp>
55
56 using namespace com::sun::star;
57 using namespace com::sun::star::uno;
58
59 #define C2U(cChar) rtl::OUString::createFromAscii(cChar)
60
61
SmartTagMgr(const rtl::OUString & rApplicationName)62 SmartTagMgr::SmartTagMgr( const rtl::OUString& rApplicationName )
63 : maApplicationName( rApplicationName ),
64 maRecognizerList(),
65 maActionList(),
66 maDisabledSmartTagTypes(),
67 maSmartTagMap(),
68 mxMSF( ::comphelper::getProcessServiceFactory() ),
69 mbLabelTextWithSmartTags(true)
70 {
71 }
72
~SmartTagMgr()73 SmartTagMgr::~SmartTagMgr()
74 {
75 }
76
Init(const rtl::OUString & rConfigurationGroupName)77 void SmartTagMgr::Init( const rtl::OUString& rConfigurationGroupName )
78 {
79 // get component context to pass to components:
80 if ( mxMSF.is() )
81 {
82 Reference< beans::XPropertySet > xPropSet = Reference< beans::XPropertySet>( mxMSF, UNO_QUERY);
83 const Any aAny = xPropSet->getPropertyValue( C2U("DefaultContext"));
84 aAny >>= mxContext;
85
86 if ( mxContext.is() )
87 {
88 PrepareConfiguration( rConfigurationGroupName );
89 ReadConfiguration( true, true );
90 RegisterListener();
91 LoadLibraries();
92 }
93 }
94 }
CreateBreakIterator() const95 void SmartTagMgr::CreateBreakIterator() const
96 {
97 if ( !mxBreakIter.is() && mxMSF.is() && mxContext.is() )
98 {
99 // get the break iterator
100 mxBreakIter.set(mxMSF->createInstance( C2U( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY);
101 }
102 }
103
104 /** Dispatches the recognize call to all installed smart tag recognizers
105 */
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) const106 void SmartTagMgr::RecognizeString( const rtl::OUString& rText,
107 const Reference< text::XTextMarkup > xMarkup,
108 const Reference< frame::XController > xController,
109 const lang::Locale& rLocale,
110 sal_uInt32 nStart, sal_uInt32 nLen ) const
111 {
112 for ( sal_uInt32 i = 0; i < maRecognizerList.size(); i++ )
113 {
114 Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i];
115
116 // if all smart tag types supported by this recognizer have been
117 // disabled, we do not have to call the recognizer:
118 bool bCallRecognizer = false;
119 const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount();
120 for ( sal_uInt32 j = 0; j < nSmartTagCount && !bCallRecognizer; ++j )
121 {
122 const rtl::OUString aSmartTagName = xRecognizer->getSmartTagName(j);
123 if ( IsSmartTagTypeEnabled( aSmartTagName ) )
124 bCallRecognizer = true;
125 }
126
127 if ( bCallRecognizer )
128 {
129 CreateBreakIterator();
130 maRecognizerList[i]->recognize( rText, nStart, nLen,
131 smarttags::SmartTagRecognizerMode_PARAGRAPH,
132 rLocale, xMarkup, maApplicationName, xController,
133 mxBreakIter );
134 }
135 }
136 }
137
RecognizeTextRange(const Reference<text::XTextRange> xRange,const Reference<text::XTextMarkup> xMarkup,const Reference<frame::XController> xController) const138 void SmartTagMgr::RecognizeTextRange(const Reference< text::XTextRange> xRange,
139 const Reference< text::XTextMarkup > xMarkup,
140 const Reference< frame::XController > xController) const
141 {
142 for ( sal_uInt32 i = 0; i < maRecognizerList.size(); i++ )
143 {
144 Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i];
145
146 Reference< smarttags::XRangeBasedSmartTagRecognizer > xRangeBasedRecognizer = Reference< smarttags::XRangeBasedSmartTagRecognizer >( xRecognizer, UNO_QUERY);
147
148 if (!xRangeBasedRecognizer.is()) continue;
149
150 // if all smart tag types supported by this recognizer have been
151 // disabled, we do not have to call the recognizer:
152 bool bCallRecognizer = false;
153 const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount();
154 for ( sal_uInt32 j = 0; j < nSmartTagCount && !bCallRecognizer; ++j )
155 {
156 const rtl::OUString aSmartTagName = xRecognizer->getSmartTagName(j);
157 if ( IsSmartTagTypeEnabled( aSmartTagName ) )
158 bCallRecognizer = true;
159 }
160
161 if ( bCallRecognizer )
162 {
163 xRangeBasedRecognizer->recognizeTextRange( xRange,
164 smarttags::SmartTagRecognizerMode_PARAGRAPH,
165 xMarkup, maApplicationName, xController);
166 }
167 }
168
169 }
170
171
172 typedef std::multimap < rtl::OUString, ActionReference >::const_iterator SmartTagMapIter;
173
GetActionSequences(Sequence<rtl::OUString> & rSmartTagTypes,Sequence<Sequence<Reference<smarttags::XSmartTagAction>>> & rActionComponentsSequence,Sequence<Sequence<sal_Int32>> & rActionIndicesSequence) const174 void SmartTagMgr::GetActionSequences( Sequence < rtl::OUString >& rSmartTagTypes,
175 Sequence < Sequence< Reference< smarttags::XSmartTagAction > > >& rActionComponentsSequence,
176 Sequence < Sequence< sal_Int32 > >& rActionIndicesSequence ) const
177 {
178 rActionComponentsSequence.realloc( rSmartTagTypes.getLength() );
179 rActionIndicesSequence.realloc( rSmartTagTypes.getLength() );
180
181 for ( sal_uInt16 j = 0; j < rSmartTagTypes.getLength(); ++j )
182 {
183 const rtl::OUString& rSmartTagType = rSmartTagTypes[j];
184
185 const sal_Int32 nNumberOfActionRefs = maSmartTagMap.count( rSmartTagType );
186
187 Sequence< Reference< smarttags::XSmartTagAction > > aActions( nNumberOfActionRefs );
188 Sequence< sal_Int32 > aIndices( nNumberOfActionRefs );
189
190 sal_uInt16 i = 0;
191 SmartTagMapIter aActionsIter;
192 SmartTagMapIter aEnd = maSmartTagMap.upper_bound( rSmartTagType );
193
194 for ( aActionsIter = maSmartTagMap.lower_bound( rSmartTagType ); aActionsIter != aEnd; ++aActionsIter )
195 {
196 aActions[ i ] = (*aActionsIter).second.mxSmartTagAction;
197 aIndices[ i++ ] = (*aActionsIter).second.mnSmartTagIndex;
198 }
199
200 rActionComponentsSequence[ j ] = aActions;
201 rActionIndicesSequence[ j ] = aIndices;
202 }
203 }
204
205 /** Returns the caption for a smart tag type.
206 */
GetSmartTagCaption(const rtl::OUString & rSmartTagType,const com::sun::star::lang::Locale & rLocale) const207 rtl::OUString SmartTagMgr::GetSmartTagCaption( const rtl::OUString& rSmartTagType, const com::sun::star::lang::Locale& rLocale ) const
208 {
209 rtl::OUString aRet;
210
211 SmartTagMapIter aLower = maSmartTagMap.lower_bound( rSmartTagType );
212
213 if ( aLower != maSmartTagMap.end() )
214 {
215 const ActionReference& rActionRef = (*aLower).second;
216 Reference< smarttags::XSmartTagAction > xAction = rActionRef.mxSmartTagAction;
217
218 if ( xAction.is() )
219 {
220 const sal_Int32 nSmartTagIndex = rActionRef.mnSmartTagIndex;
221 aRet = xAction->getSmartTagCaption( nSmartTagIndex, rLocale );
222 }
223 }
224
225 return aRet;
226 }
227
228
229 /** Returns true if the given smart tag type is enabled.
230 */
IsSmartTagTypeEnabled(const rtl::OUString & rSmartTagType) const231 bool SmartTagMgr::IsSmartTagTypeEnabled( const rtl::OUString& rSmartTagType ) const
232 {
233 return maDisabledSmartTagTypes.end() == maDisabledSmartTagTypes.find( rSmartTagType );
234 }
235
236 /** Writes currently disabled smart tag types to configuration.
237 */
WriteConfiguration(const bool * pIsLabelTextWithSmartTags,const std::vector<rtl::OUString> * pDisabledTypes) const238 void SmartTagMgr::WriteConfiguration( const bool* pIsLabelTextWithSmartTags,
239 const std::vector< rtl::OUString >* pDisabledTypes ) const
240 {
241 if ( mxConfigurationSettings.is() )
242 {
243 bool bCommit = false;
244
245 if ( pIsLabelTextWithSmartTags )
246 {
247 const Any aEnabled = makeAny( *pIsLabelTextWithSmartTags );
248
249 try
250 {
251 mxConfigurationSettings->setPropertyValue( C2U("RecognizeSmartTags"), aEnabled );
252 bCommit = true;
253 }
254 catch ( ::com::sun::star::uno::Exception& )
255 {
256 }
257 }
258
259 if ( pDisabledTypes )
260 {
261 const sal_Int32 nNumberOfDisabledSmartTagTypes = pDisabledTypes->size();
262 Sequence< rtl::OUString > aTypes( nNumberOfDisabledSmartTagTypes );
263
264 std::vector< rtl::OUString >::const_iterator aIter;
265 sal_Int32 nCount = 0;
266 for ( aIter = pDisabledTypes->begin(); aIter != pDisabledTypes->end(); ++aIter )
267 aTypes[ nCount++ ] = *aIter;
268
269 const Any aNewTypes = makeAny( aTypes );
270
271 try
272 {
273 mxConfigurationSettings->setPropertyValue( C2U("ExcludedSmartTagTypes"), aNewTypes );
274 bCommit = true;
275 }
276 catch ( ::com::sun::star::uno::Exception& )
277 {
278 }
279 }
280
281 if ( bCommit )
282 {
283 try
284 {
285 Reference< util::XChangesBatch >( mxConfigurationSettings, UNO_QUERY_THROW )->commitChanges();
286 }
287 catch ( ::com::sun::star::uno::Exception& )
288 {
289 }
290 }
291 }
292 }
293
294 // ::com::sun::star::util::XModifyListener
modified(const lang::EventObject &)295 void SmartTagMgr::modified( const lang::EventObject& ) throw( RuntimeException )
296 {
297 vos::OGuard aGuard(Application::GetSolarMutex());
298
299 maRecognizerList.clear();
300 maActionList.clear();
301 maSmartTagMap.clear();
302
303 LoadLibraries();
304 }
305
306 // ::com::sun::star::lang::XEventListener
disposing(const lang::EventObject & rEvent)307 void SmartTagMgr::disposing( const lang::EventObject& rEvent ) throw( RuntimeException )
308 {
309 vos::OGuard aGuard(Application::GetSolarMutex());
310
311 uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY );
312 uno::Reference< util::XModifyBroadcaster > xMB(xModel, uno::UNO_QUERY);
313 uno::Reference< util::XChangesNotifier > xCN(xModel, uno::UNO_QUERY);
314
315 try
316 {
317 if( xMB.is() )
318 {
319 uno::Reference< util::XModifyListener > xListener( this );
320 xMB->removeModifyListener( xListener );
321 }
322 else if ( xCN.is() )
323 {
324 uno::Reference< util::XChangesListener > xListener( this );
325 xCN->removeChangesListener( xListener );
326 }
327 }
328 catch(Exception& )
329 {
330 }
331 }
332
333 // ::com::sun::star::util::XChangesListener
changesOccurred(const util::ChangesEvent & rEvent)334 void SmartTagMgr::changesOccurred( const util::ChangesEvent& rEvent ) throw( RuntimeException)
335 {
336 vos::OGuard aGuard(Application::GetSolarMutex());
337
338 const util::ElementChange* pElementChanges = rEvent.Changes.getConstArray();
339 const sal_Int32 nNumberOfChanges = rEvent.Changes.getLength();
340 bool bExcludedTypes = false;
341 bool bRecognize = false;
342
343 for( sal_Int32 i = 0; i < nNumberOfChanges; ++i)
344 {
345 rtl::OUString sTemp;
346 pElementChanges[i].Accessor >>= sTemp;
347
348 if ( sTemp == C2U( "ExcludedSmartTagTypes" ) )
349 bExcludedTypes = true;
350 else if ( sTemp == C2U( "RecognizeSmartTags" ) )
351 bRecognize = true;
352 }
353
354 ReadConfiguration( bExcludedTypes, bRecognize );
355 }
356
357 //------------- PRIVATE -----------------------------------------------
358
359 /**
360 */
LoadLibraries()361 void SmartTagMgr::LoadLibraries()
362 {
363 Reference< container::XContentEnumerationAccess > rContent( mxMSF , UNO_QUERY );
364 if ( !rContent.is() )
365 return;
366
367 // load recognizers: No recognizers -> nothing to do.
368 Reference < container::XEnumeration > rEnum = rContent->createContentEnumeration( C2U("com.sun.star.smarttags.SmartTagRecognizer"));
369 if ( !rEnum.is() || !rEnum->hasMoreElements() )
370 return;
371
372 // iterate over all implementations of the smart tag recognizer service:
373 while( rEnum->hasMoreElements())
374 {
375 const Any a = rEnum->nextElement();
376 Reference< lang::XSingleComponentFactory > xSCF;
377 Reference< lang::XServiceInfo > xsInfo;
378
379 if (a >>= xsInfo)
380 xSCF = Reference< lang::XSingleComponentFactory >(xsInfo, UNO_QUERY);
381 else
382 continue;
383
384 Reference< smarttags::XSmartTagRecognizer > xLib ( xSCF->
385 createInstanceWithContext(mxContext), UNO_QUERY );
386
387 if (!xLib.is())
388 continue;
389
390 xLib->initialize( Sequence< Any >() );
391 maRecognizerList.push_back(xLib);
392 }
393
394 // load actions: No actions -> nothing to do.
395 rEnum = rContent->createContentEnumeration( C2U("com.sun.star.smarttags.SmartTagAction"));
396 if ( !rEnum.is() )
397 return;
398
399 // iterate over all implementations of the smart tag action service:
400 while( rEnum->hasMoreElements())
401 {
402 const Any a = rEnum->nextElement();
403 Reference< lang::XServiceInfo > xsInfo;
404 Reference< lang::XSingleComponentFactory > xSCF;
405
406 if (a >>= xsInfo)
407 xSCF = Reference< lang::XSingleComponentFactory >(xsInfo, UNO_QUERY);
408 else
409 continue;
410
411 Reference< smarttags::XSmartTagAction > xLib ( xSCF->
412 createInstanceWithContext(mxContext), UNO_QUERY );
413
414 if (!xLib.is())
415 continue;
416
417 xLib->initialize( Sequence< Any >() );
418 maActionList.push_back(xLib);
419 }
420
421 AssociateActionsWithRecognizers();
422
423 }
424
425 /**
426 */
PrepareConfiguration(const rtl::OUString & rConfigurationGroupName)427 void SmartTagMgr::PrepareConfiguration( const rtl::OUString& rConfigurationGroupName )
428 {
429 Any aAny = makeAny( C2U( "/org.openoffice.Office.Common/SmartTags/" ) + rConfigurationGroupName );
430 beans::PropertyValue aPathArgument;
431 aPathArgument.Name = C2U( "nodepath" );
432 aPathArgument.Value = aAny;
433 Sequence< Any > aArguments( 1 );
434 aArguments[ 0 ] <<= aPathArgument;
435 Reference< lang::XMultiServiceFactory > xConfProv( mxMSF->createInstance(C2U ("com.sun.star.configuration.ConfigurationProvider")), UNO_QUERY );
436
437 if ( !xConfProv.is() )
438 return;
439
440 // try to get read-write access to configuration:
441 Reference< XInterface > xConfigurationAccess;
442 try
443 {
444 xConfigurationAccess = xConfProv->createInstanceWithArguments(
445 C2U("com.sun.star.configuration.ConfigurationUpdateAccess" ), aArguments );
446 }
447 catch ( uno::Exception& )
448 {
449 }
450
451 // fallback: try read-only access to configuration:
452 if ( !xConfigurationAccess.is() )
453 {
454 try
455 {
456 xConfigurationAccess = xConfProv->createInstanceWithArguments(
457 C2U("com.sun.star.configuration.ConfigurationAccess" ), aArguments );
458 }
459 catch ( uno::Exception& )
460 {
461 }
462 }
463
464 if ( xConfigurationAccess.is() )
465 {
466 mxConfigurationSettings = Reference< beans::XPropertySet >( xConfigurationAccess, UNO_QUERY );
467 }
468 }
469
470
ReadConfiguration(bool bExcludedTypes,bool bRecognize)471 void SmartTagMgr::ReadConfiguration( bool bExcludedTypes, bool bRecognize )
472 {
473 if ( mxConfigurationSettings.is() )
474 {
475 if ( bExcludedTypes )
476 {
477 maDisabledSmartTagTypes.clear();
478
479 Any aAny = mxConfigurationSettings->getPropertyValue( C2U("ExcludedSmartTagTypes") );
480 Sequence< rtl::OUString > aValues;
481 aAny >>= aValues;
482
483 const sal_Int32 nValues = aValues.getLength();
484
485 for ( sal_Int32 nI = 0; nI < nValues; ++nI )
486 maDisabledSmartTagTypes.insert( aValues[nI] );
487 }
488
489 if ( bRecognize )
490 {
491 Any aAny = mxConfigurationSettings->getPropertyValue( C2U("RecognizeSmartTags") );
492 sal_Bool bValue = sal_True;
493 aAny >>= bValue;
494
495 mbLabelTextWithSmartTags = bValue;
496 }
497 }
498 }
499
500 /**
501 */
RegisterListener()502 void SmartTagMgr::RegisterListener()
503 {
504 // register as listener at package manager
505 try
506 {
507 Reference<deployment::XExtensionManager> xExtensionManager(
508 deployment::ExtensionManager::get( mxContext ) );
509 Reference< util::XModifyBroadcaster > xMB ( xExtensionManager, UNO_QUERY_THROW );
510
511 Reference< util::XModifyListener > xListener( this );
512 xMB->addModifyListener( xListener );
513 }
514 catch ( uno::Exception& )
515 {
516 }
517
518 // register as listener at configuration
519 try
520 {
521 Reference<util::XChangesNotifier> xCN( mxConfigurationSettings, UNO_QUERY_THROW );
522 Reference< util::XChangesListener > xListener( this );
523 xCN->addChangesListener( xListener );
524 }
525 catch ( uno::Exception& )
526 {
527 }
528 }
529
530 typedef std::pair < const rtl::OUString, ActionReference > SmartTagMapElement;
531
532 /** Sets up a map that maps smart tag type names to actions references.
533 */
AssociateActionsWithRecognizers()534 void SmartTagMgr::AssociateActionsWithRecognizers()
535 {
536 const sal_uInt32 nActionLibCount = maActionList.size();
537 const sal_uInt32 nRecognizerCount = maRecognizerList.size();
538
539 for ( sal_uInt32 i = 0; i < nRecognizerCount; ++i )
540 {
541 Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i];
542 const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount();
543 for ( sal_uInt32 j = 0; j < nSmartTagCount; ++j )
544 {
545 const rtl::OUString aSmartTagName = xRecognizer->getSmartTagName(j);
546
547 // check if smart tag type has already been processed:
548 if ( maSmartTagMap.find( aSmartTagName ) != maSmartTagMap.end() )
549 continue;
550
551 bool bFound = false;
552 for ( sal_uInt32 k = 0; k < nActionLibCount; ++k )
553 {
554 Reference< smarttags::XSmartTagAction > xActionLib = maActionList[k];
555 const sal_uInt32 nSmartTagCountInActionLib = xActionLib->getSmartTagCount();
556 for ( sal_uInt32 l = 0; l < nSmartTagCountInActionLib; ++l )
557 {
558 const rtl::OUString aSmartTagNameInActionLib = xActionLib->getSmartTagName(l);
559 if ( aSmartTagName.equals( aSmartTagNameInActionLib ) )
560 {
561 // found actions and recognizer for same smarttag
562 ActionReference aActionRef( xActionLib, l );
563
564 // add recognizer/action pair to map
565 maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef ));
566
567 bFound = true;
568 }
569 }
570 }
571
572 if ( !bFound )
573 {
574 // insert 'empty' action reference if there is no action associated with
575 // the current smart tag type:
576 Reference< smarttags::XSmartTagAction > xActionLib;
577 ActionReference aActionRef( xActionLib, 0 );
578
579 // add recognizer/action pair to map
580 maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef ));
581 }
582 }
583 }
584 }
585
586