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