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 22 : PrepareConfiguration( rConfigurationGroupName );
73 22 : ReadConfiguration( true, true );
74 22 : RegisterListener();
75 22 : LoadLibraries();
76 22 : }
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 ( sal_uInt32 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 ( sal_uInt32 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_uInt16 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 18 : void SmartTagMgr::disposing( const lang::EventObject& rEvent ) throw( RuntimeException, std::exception )
289 : {
290 18 : SolarMutexGuard aGuard;
291 :
292 36 : uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY );
293 36 : uno::Reference< util::XModifyBroadcaster > xMB(xModel, uno::UNO_QUERY);
294 36 : uno::Reference< util::XChangesNotifier > xCN(xModel, uno::UNO_QUERY);
295 :
296 : try
297 : {
298 18 : if( xMB.is() )
299 : {
300 0 : uno::Reference< util::XModifyListener > xListener( this );
301 0 : xMB->removeModifyListener( xListener );
302 : }
303 18 : 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 18 : }
312 18 : }
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 : //------------- PRIVATE -----------------------------------------------
339 :
340 : /**
341 : */
342 26 : void SmartTagMgr::LoadLibraries()
343 : {
344 26 : Reference< container::XContentEnumerationAccess > rContent( mxContext->getServiceManager(), UNO_QUERY_THROW );
345 :
346 : // load recognizers: No recognizers -> nothing to do.
347 26 : Reference < container::XEnumeration > rEnum = rContent->createContentEnumeration( "com.sun.star.smarttags.SmartTagRecognizer");
348 26 : if ( !rEnum.is() || !rEnum->hasMoreElements() )
349 26 : return;
350 :
351 : // iterate over all implementations of the smart tag recognizer service:
352 0 : while( rEnum->hasMoreElements())
353 : {
354 0 : const Any a = rEnum->nextElement();
355 0 : Reference< lang::XSingleComponentFactory > xSCF;
356 0 : Reference< lang::XServiceInfo > xsInfo;
357 :
358 0 : if (a >>= xsInfo)
359 0 : xSCF = Reference< lang::XSingleComponentFactory >(xsInfo, UNO_QUERY);
360 : else
361 0 : continue;
362 :
363 0 : Reference< smarttags::XSmartTagRecognizer > xLib ( xSCF->
364 0 : createInstanceWithContext(mxContext), UNO_QUERY );
365 :
366 0 : if (!xLib.is())
367 0 : continue;
368 :
369 0 : xLib->initialize( Sequence< Any >() );
370 0 : maRecognizerList.push_back(xLib);
371 0 : }
372 :
373 : // load actions: No actions -> nothing to do.
374 0 : rEnum = rContent->createContentEnumeration( "com.sun.star.smarttags.SmartTagAction");
375 0 : if ( !rEnum.is() )
376 0 : return;
377 :
378 : // iterate over all implementations of the smart tag action service:
379 0 : while( rEnum->hasMoreElements())
380 : {
381 0 : const Any a = rEnum->nextElement();
382 0 : Reference< lang::XServiceInfo > xsInfo;
383 0 : Reference< lang::XSingleComponentFactory > xSCF;
384 :
385 0 : if (a >>= xsInfo)
386 0 : xSCF = Reference< lang::XSingleComponentFactory >(xsInfo, UNO_QUERY);
387 : else
388 0 : continue;
389 :
390 0 : Reference< smarttags::XSmartTagAction > xLib ( xSCF->
391 0 : createInstanceWithContext(mxContext), UNO_QUERY );
392 :
393 0 : if (!xLib.is())
394 0 : continue;
395 :
396 0 : xLib->initialize( Sequence< Any >() );
397 0 : maActionList.push_back(xLib);
398 0 : }
399 :
400 0 : AssociateActionsWithRecognizers();
401 :
402 : }
403 :
404 : /**
405 : */
406 22 : void SmartTagMgr::PrepareConfiguration( const OUString& rConfigurationGroupName )
407 : {
408 22 : Any aAny = makeAny( "/org.openoffice.Office.Common/SmartTags/" + rConfigurationGroupName );
409 44 : beans::PropertyValue aPathArgument;
410 22 : aPathArgument.Name = "nodepath";
411 22 : aPathArgument.Value = aAny;
412 44 : Sequence< Any > aArguments( 1 );
413 22 : aArguments[ 0 ] <<= aPathArgument;
414 44 : Reference< lang::XMultiServiceFactory > xConfProv = configuration::theDefaultProvider::get( mxContext );
415 :
416 : // try to get read-write access to configuration:
417 44 : Reference< XInterface > xConfigurationAccess;
418 : try
419 : {
420 66 : xConfigurationAccess = xConfProv->createInstanceWithArguments(
421 44 : "com.sun.star.configuration.ConfigurationUpdateAccess", aArguments );
422 : }
423 0 : catch ( uno::Exception& )
424 : {
425 : }
426 :
427 : // fallback: try read-only access to configuration:
428 22 : if ( !xConfigurationAccess.is() )
429 : {
430 : try
431 : {
432 0 : xConfigurationAccess = xConfProv->createInstanceWithArguments(
433 0 : "com.sun.star.configuration.ConfigurationAccess", aArguments );
434 : }
435 0 : catch ( uno::Exception& )
436 : {
437 : }
438 : }
439 :
440 22 : if ( xConfigurationAccess.is() )
441 : {
442 22 : mxConfigurationSettings = Reference< beans::XPropertySet >( xConfigurationAccess, UNO_QUERY );
443 22 : }
444 22 : }
445 :
446 :
447 22 : void SmartTagMgr::ReadConfiguration( bool bExcludedTypes, bool bRecognize )
448 : {
449 22 : if ( mxConfigurationSettings.is() )
450 : {
451 22 : if ( bExcludedTypes )
452 : {
453 22 : maDisabledSmartTagTypes.clear();
454 :
455 22 : Any aAny = mxConfigurationSettings->getPropertyValue( "ExcludedSmartTagTypes" );
456 44 : Sequence< OUString > aValues;
457 22 : aAny >>= aValues;
458 :
459 22 : const sal_Int32 nValues = aValues.getLength();
460 :
461 22 : for ( sal_Int32 nI = 0; nI < nValues; ++nI )
462 22 : maDisabledSmartTagTypes.insert( aValues[nI] );
463 : }
464 :
465 22 : if ( bRecognize )
466 : {
467 22 : Any aAny = mxConfigurationSettings->getPropertyValue( "RecognizeSmartTags" );
468 22 : sal_Bool bValue = sal_True;
469 22 : aAny >>= bValue;
470 :
471 22 : mbLabelTextWithSmartTags = bValue;
472 : }
473 : }
474 22 : }
475 :
476 : /**
477 : */
478 22 : void SmartTagMgr::RegisterListener()
479 : {
480 : // register as listener at package manager
481 : try
482 : {
483 : Reference<deployment::XExtensionManager> xExtensionManager(
484 22 : deployment::ExtensionManager::get( mxContext ) );
485 38 : Reference< util::XModifyBroadcaster > xMB ( xExtensionManager, UNO_QUERY_THROW );
486 :
487 38 : Reference< util::XModifyListener > xListener( this );
488 38 : xMB->addModifyListener( xListener );
489 : }
490 3 : catch ( uno::Exception& )
491 : {
492 : }
493 :
494 : // register as listener at configuration
495 : try
496 : {
497 22 : Reference<util::XChangesNotifier> xCN( mxConfigurationSettings, UNO_QUERY_THROW );
498 44 : Reference< util::XChangesListener > xListener( this );
499 44 : xCN->addChangesListener( xListener );
500 : }
501 0 : catch ( uno::Exception& )
502 : {
503 : }
504 22 : }
505 :
506 : typedef std::pair < const OUString, ActionReference > SmartTagMapElement;
507 :
508 : /** Sets up a map that maps smart tag type names to actions references.
509 : */
510 0 : void SmartTagMgr::AssociateActionsWithRecognizers()
511 : {
512 0 : const sal_uInt32 nActionLibCount = maActionList.size();
513 0 : const sal_uInt32 nRecognizerCount = maRecognizerList.size();
514 :
515 0 : for ( sal_uInt32 i = 0; i < nRecognizerCount; ++i )
516 : {
517 0 : Reference < smarttags::XSmartTagRecognizer > xRecognizer = maRecognizerList[i];
518 0 : const sal_uInt32 nSmartTagCount = xRecognizer->getSmartTagCount();
519 0 : for ( sal_uInt32 j = 0; j < nSmartTagCount; ++j )
520 : {
521 0 : const OUString aSmartTagName = xRecognizer->getSmartTagName(j);
522 :
523 : // check if smart tag type has already been processed:
524 0 : if ( maSmartTagMap.find( aSmartTagName ) != maSmartTagMap.end() )
525 0 : continue;
526 :
527 0 : bool bFound = false;
528 0 : for ( sal_uInt32 k = 0; k < nActionLibCount; ++k )
529 : {
530 0 : Reference< smarttags::XSmartTagAction > xActionLib = maActionList[k];
531 0 : const sal_uInt32 nSmartTagCountInActionLib = xActionLib->getSmartTagCount();
532 0 : for ( sal_uInt32 l = 0; l < nSmartTagCountInActionLib; ++l )
533 : {
534 0 : const OUString aSmartTagNameInActionLib = xActionLib->getSmartTagName(l);
535 0 : if ( aSmartTagName.equals( aSmartTagNameInActionLib ) )
536 : {
537 : // found actions and recognizer for same smarttag
538 0 : ActionReference aActionRef( xActionLib, l );
539 :
540 : // add recognizer/action pair to map
541 0 : maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef ));
542 :
543 0 : bFound = true;
544 : }
545 0 : }
546 0 : }
547 :
548 0 : if ( !bFound )
549 : {
550 : // insert 'empty' action reference if there is no action associated with
551 : // the current smart tag type:
552 0 : Reference< smarttags::XSmartTagAction > xActionLib;
553 0 : ActionReference aActionRef( xActionLib, 0 );
554 :
555 : // add recognizer/action pair to map
556 0 : maSmartTagMap.insert( SmartTagMapElement( aSmartTagName, aActionRef ));
557 : }
558 0 : }
559 0 : }
560 0 : }
561 :
562 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|