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