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