xref: /AOO41X/main/unotools/source/config/eventcfg.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_unotools.hxx"
30 
31 #include <unotools/eventcfg.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <unotools/configitem.hxx>
34 #include <tools/debug.hxx>
35 #include <com/sun/star/uno/Any.hxx>
36 #include <com/sun/star/uno/Sequence.hxx>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <cppuhelper/weakref.hxx>
39 
40 #ifndef __SGI_STL_HASH_MAP
41 #include <hash_map>
42 #endif
43 #include <tools/urlobj.hxx>
44 #include <rtl/ustrbuf.hxx>
45 
46 #include <itemholder1.hxx>
47 
48 #include <algorithm>
49 
50 using namespace ::std					;
51 using namespace ::utl					;
52 using namespace ::rtl					;
53 using namespace ::osl					;
54 using namespace ::com::sun::star::uno	;
55 using namespace ::com::sun::star;
56 
57 #define ROOTNODE_EVENTS OUString(RTL_CONSTASCII_USTRINGPARAM("Office.Events/ApplicationEvents" ))
58 #define PATHDELIMITER OUString(RTL_CONSTASCII_USTRINGPARAM("/"))
59 #define SETNODE_BINDINGS OUString(RTL_CONSTASCII_USTRINGPARAM("Bindings" ))
60 #define PROPERTYNAME_BINDINGURL OUString(RTL_CONSTASCII_USTRINGPARAM("BindingURL"))
61 
62 const char* pEventAsciiNames[] =
63 {
64 "OnStartApp",
65 "OnCloseApp",
66 "OnCreate",
67 "OnNew",
68 "OnLoadFinished",
69 "OnLoad",
70 "OnPrepareUnload",
71 "OnUnload",
72 "OnSave",
73 "OnSaveDone",
74 "OnSaveFailed",
75 "OnSaveAs",
76 "OnSaveAsDone",
77 "OnSaveAsFailed",
78 "OnCopyTo",
79 "OnCopyToDone",
80 "OnCopyToFailed",
81 "OnFocus",
82 "OnUnfocus",
83 "OnPrint",
84 "OnViewCreated",
85 "OnPrepareViewClosing",
86 "OnViewClosed",
87 "OnModifyChanged",
88 "OnTitleChanged",
89 "OnVisAreaChanged",
90 "OnModeChanged",
91 "OnStorageChanged"
92 };
93 
94 GlobalEventConfig_Impl::GlobalEventConfig_Impl()
95     :   ConfigItem( ROOTNODE_EVENTS, CONFIG_MODE_IMMEDIATE_UPDATE )
96 {
97     // the supported event names
98     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_STARTAPP] ) );
99     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_CLOSEAPP] ) );
100     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_DOCCREATED] ) );
101     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_CREATEDOC] ) );
102     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_LOADFINISHED] ) );
103     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_OPENDOC] ) );
104     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_PREPARECLOSEDOC] ) );
105     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_CLOSEDOC] ) );
106     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVEDOC] ) );
107     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVEDOCDONE] ) );
108     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVEDOCFAILED] ) );
109     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVEASDOC] ) );
110     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVEASDOCDONE] ) );
111     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVEASDOCFAILED] ) );
112     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVETODOC] ) );
113     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVETODOCDONE] ) );
114     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_SAVETODOCFAILED] ) );
115     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_ACTIVATEDOC] ) );
116     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_DEACTIVATEDOC] ) );
117     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_PRINTDOC] ) );
118     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_VIEWCREATED] ) );
119     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_PREPARECLOSEVIEW] ) );
120     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_CLOSEVIEW] ) );
121     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_MODIFYCHANGED] ) );
122     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_TITLECHANGED] ) );
123     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_VISAREACHANGED] ) );
124     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_MODECHANGED] ) );
125     m_supportedEvents.push_back(::rtl::OUString::createFromAscii( pEventAsciiNames[STR_EVENT_STORAGECHANGED] ) );
126 
127     initBindingInfo();
128 
129 /*TODO: Not used in the moment! see Notify() ...
130 	// Enable notification mechanism of our baseclass.
131 	// We need it to get information about changes outside these class on our used configuration keys! */
132     Sequence< OUString > aNotifySeq( 1 );
133     aNotifySeq[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "Events" ));
134     EnableNotification( aNotifySeq, sal_True );
135 }
136 
137 //*****************************************************************************************************************
138 //	destructor
139 //*****************************************************************************************************************
140 GlobalEventConfig_Impl::~GlobalEventConfig_Impl()
141 {
142 	// We must save our current values .. if user forget it!
143 	if( IsModified() == sal_True )
144 	{
145 		Commit();
146 	}
147 }
148 
149 ::rtl::OUString GlobalEventConfig_Impl::GetEventName( sal_Int32 nIndex )
150 {
151 	if ( nIndex < (sal_Int32) m_supportedEvents.size() )
152 		return m_supportedEvents[nIndex];
153 	else
154 		return rtl::OUString();
155 }
156 
157 //*****************************************************************************************************************
158 //	public method
159 //*****************************************************************************************************************
160 void GlobalEventConfig_Impl::Notify( const Sequence< OUString >& )
161 {
162     MutexGuard aGuard( GlobalEventConfig::GetOwnStaticMutex() );
163 
164     initBindingInfo();
165 
166     // dont forget to update all existing frames and her might cached dispatch objects!
167     // But look for already killed frames. We hold weak references instead of hard ones ...
168     for (FrameVector::const_iterator pIt  = m_lFrames.begin();
169                                         pIt != m_lFrames.end()  ;
170                                       ++pIt                     )
171     {
172         ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame(pIt->get(), ::com::sun::star::uno::UNO_QUERY);
173         if (xFrame.is())
174             xFrame->contextChanged();
175     }
176 }
177 
178 //*****************************************************************************************************************
179 //	public method
180 //*****************************************************************************************************************
181 void GlobalEventConfig_Impl::Commit()
182 {
183     //DF need to check it this is correct??
184     OSL_TRACE("In GlobalEventConfig_Impl::Commit");
185     EventBindingHash::const_iterator it = m_eventBindingHash.begin();
186     EventBindingHash::const_iterator it_end = m_eventBindingHash.end();
187     // clear the existing nodes
188     ClearNodeSet( SETNODE_BINDINGS );
189     Sequence< beans::PropertyValue > seqValues( 1 );
190     OUString sNode;
191     static const OUString sPrefix(SETNODE_BINDINGS + PATHDELIMITER + OUString::createFromAscii("BindingType['"));
192     static const OUString sPostfix(OUString::createFromAscii("']") + PATHDELIMITER + PROPERTYNAME_BINDINGURL);
193     //step through the list of events
194     for(int i=0;it!=it_end;++it,++i)
195     {
196         //no point in writing out empty bindings!
197         if(it->second.getLength() == 0 )
198             continue;
199         sNode = sPrefix + it->first + sPostfix;
200         OSL_TRACE("writing binding for: %s",::rtl::OUStringToOString(sNode , RTL_TEXTENCODING_ASCII_US ).pData->buffer);
201         seqValues[ 0 ].Name = sNode;
202         seqValues[ 0 ].Value <<= it->second;
203         //write the data to the registry
204         SetSetProperties(SETNODE_BINDINGS,seqValues);
205     }
206 }
207 
208 //*****************************************************************************************************************
209 //  public method
210 //*****************************************************************************************************************
211 void GlobalEventConfig_Impl::EstablishFrameCallback(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame)
212 {
213     // check if frame already exists inside list
214     // ignore double registrations
215     // every frame must be notified one times only!
216     ::com::sun::star::uno::WeakReference< ::com::sun::star::frame::XFrame > xWeak(xFrame);
217     FrameVector::const_iterator pIt = ::std::find(m_lFrames.begin(), m_lFrames.end(), xWeak);
218     if (pIt == m_lFrames.end())
219         m_lFrames.push_back(xWeak);
220 }
221 
222 //*****************************************************************************************************************
223 //	private method
224 //*****************************************************************************************************************
225 void GlobalEventConfig_Impl::initBindingInfo()
226 {
227 	// Get ALL names of current existing list items in configuration!
228     Sequence< OUString > lEventNames      = GetNodeNames( SETNODE_BINDINGS, utl::CONFIG_NAME_LOCAL_PATH );
229 
230 	OUString aSetNode( SETNODE_BINDINGS );
231 	aSetNode += PATHDELIMITER;
232 
233 	OUString aCommandKey( PATHDELIMITER );
234 	aCommandKey += PROPERTYNAME_BINDINGURL;
235 
236 	// Expand all keys
237     Sequence< OUString > lMacros(1);
238 	for (sal_Int32 i=0; i<lEventNames.getLength(); ++i )
239 	{
240 		OUStringBuffer aBuffer( 32 );
241 		aBuffer.append( aSetNode );
242 		aBuffer.append( lEventNames[i] );
243 		aBuffer.append( aCommandKey );
244 		lMacros[0] = aBuffer.makeStringAndClear();
245         OSL_TRACE("reading binding for: %s",::rtl::OUStringToOString(lMacros[0] , RTL_TEXTENCODING_ASCII_US ).pData->buffer);
246         Sequence< Any > lValues = GetProperties( lMacros );
247         OUString sMacroURL;
248         if( lValues.getLength() > 0 )
249         {
250             lValues[0] >>= sMacroURL;
251             sal_Int32 startIndex = lEventNames[i].indexOf('\'');
252             sal_Int32 endIndex =  lEventNames[i].lastIndexOf('\'');
253             if( startIndex >=0 && endIndex > 0 )
254             {
255                 startIndex++;
256                 OUString eventName = lEventNames[i].copy(startIndex,endIndex-startIndex);
257                 m_eventBindingHash[ eventName ] = sMacroURL;
258             }
259         }
260 	}
261 }
262 
263 Reference< container::XNameReplace > SAL_CALL GlobalEventConfig_Impl::getEvents() throw (::com::sun::star::uno::RuntimeException)
264 {
265     //how to return this object as an XNameReplace?
266     Reference< container::XNameReplace > ret;
267     return ret;
268 }
269 
270 void SAL_CALL GlobalEventConfig_Impl::replaceByName( const OUString& aName, const Any& aElement ) throw (lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
271 {
272     Sequence< beans::PropertyValue > props;
273     //DF should we prepopulate the hash with a list of valid event Names?
274     if( sal_False == ( aElement >>= props ) )
275     {
276         throw lang::IllegalArgumentException( OUString(),
277                 Reference< XInterface > (), 2);
278     }
279     OUString macroURL;
280     sal_Int32 nPropCount = props.getLength();
281     for( sal_Int32 index = 0 ; index < nPropCount ; ++index )
282     {
283         if ( props[ index ].Name.compareToAscii( "Script" ) == 0 )
284             props[ index ].Value >>= macroURL;
285     }
286     m_eventBindingHash[ aName ] = macroURL;
287     SetModified();
288 }
289 
290 Any SAL_CALL GlobalEventConfig_Impl::getByName( const OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
291 {
292     Any aRet;
293     Sequence< beans::PropertyValue > props(2);
294     props[0].Name = OUString::createFromAscii("EventType");
295     props[0].Value <<= OUString::createFromAscii("Script");
296     props[1].Name = OUString::createFromAscii("Script");
297     EventBindingHash::const_iterator it = m_eventBindingHash.find( aName );
298     if( it != m_eventBindingHash.end() )
299     {
300         props[1].Value <<= it->second;
301     }
302     else
303     {
304         // not yet accessed - is it a supported name?
305         SupportedEventsVector::const_iterator pos = ::std::find(
306             m_supportedEvents.begin(), m_supportedEvents.end(), aName );
307         if ( pos == m_supportedEvents.end() )
308             throw container::NoSuchElementException( aName, NULL );
309 
310         props[1].Value <<= OUString();
311     }
312     aRet <<= props;
313     return aRet;
314 }
315 
316 Sequence< OUString > SAL_CALL GlobalEventConfig_Impl::getElementNames(  ) throw (RuntimeException)
317 {
318     const ::rtl::OUString* pRet = m_supportedEvents.empty() ? NULL : &m_supportedEvents[0];
319 	return uno::Sequence< ::rtl::OUString >(pRet, m_supportedEvents.size());
320 }
321 
322 sal_Bool SAL_CALL GlobalEventConfig_Impl::hasByName( const OUString& aName ) throw (RuntimeException)
323 {
324     if ( m_eventBindingHash.find( aName ) != m_eventBindingHash.end() )
325         return sal_True;
326 
327     // never accessed before - is it supported in general?
328     SupportedEventsVector::const_iterator pos = ::std::find(
329         m_supportedEvents.begin(), m_supportedEvents.end(), aName );
330     if ( pos != m_supportedEvents.end() )
331         return sal_True;
332 
333     return sal_False;
334 }
335 
336 Type SAL_CALL GlobalEventConfig_Impl::getElementType(  ) throw (RuntimeException)
337 {
338     //DF definitly not sure about this??
339     return ::getCppuType((const Sequence<beans::PropertyValue>*)0);
340 }
341 
342 sal_Bool SAL_CALL GlobalEventConfig_Impl::hasElements(  ) throw (RuntimeException)
343 {
344     return ( m_eventBindingHash.empty() );
345 }
346 
347 // and now the wrapper
348 
349 
350 //initialize static member
351 GlobalEventConfig_Impl*     GlobalEventConfig::m_pImpl = NULL  ;
352 sal_Int32                   GlobalEventConfig::m_nRefCount      = 0     ;
353 
354 GlobalEventConfig::GlobalEventConfig()
355 {
356     // Global access, must be guarded (multithreading!).
357     MutexGuard aGuard( GetOwnStaticMutex() );
358 	// Increase our refcount ...
359 	++m_nRefCount;
360 	// ... and initialize our data container only if it not already exist!
361     if( m_pImpl == NULL )
362 	{
363         m_pImpl = new GlobalEventConfig_Impl;
364         ItemHolder1::holdConfigItem(E_EVENTCFG);
365 	}
366 }
367 
368 GlobalEventConfig::~GlobalEventConfig()
369 {
370     // Global access, must be guarded (multithreading!)
371     MutexGuard aGuard( GetOwnStaticMutex() );
372 	// Decrease our refcount.
373 	--m_nRefCount;
374 	// If last instance was deleted ...
375 	// we must destroy our static data container!
376     if( m_nRefCount <= 0 )
377 	{
378 		delete m_pImpl;
379 		m_pImpl = NULL;
380 	}
381 }
382 
383 void GlobalEventConfig::EstablishFrameCallback(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame)
384 {
385     MutexGuard aGuard( GetOwnStaticMutex() );
386     m_pImpl->EstablishFrameCallback( xFrame );
387 }
388 
389 Reference< container::XNameReplace > SAL_CALL GlobalEventConfig::getEvents() throw (::com::sun::star::uno::RuntimeException)
390 {
391     MutexGuard aGuard( GetOwnStaticMutex() );
392     Reference< container::XNameReplace > ret(this);
393     return ret;
394 }
395 
396 void SAL_CALL GlobalEventConfig::replaceByName( const OUString& aName, const Any& aElement ) throw (lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
397 {
398     MutexGuard aGuard( GetOwnStaticMutex() );
399     m_pImpl->replaceByName( aName, aElement );
400 }
401 Any SAL_CALL GlobalEventConfig::getByName( const OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
402 {
403     MutexGuard aGuard( GetOwnStaticMutex() );
404     return m_pImpl->getByName( aName );
405 }
406 Sequence< OUString > SAL_CALL GlobalEventConfig::getElementNames(  ) throw (RuntimeException)
407 {
408     MutexGuard aGuard( GetOwnStaticMutex() );
409     return m_pImpl->getElementNames( );
410 }
411 sal_Bool SAL_CALL GlobalEventConfig::hasByName( const OUString& aName ) throw (RuntimeException)
412 {
413     MutexGuard aGuard( GetOwnStaticMutex() );
414     return m_pImpl->hasByName( aName );
415 }
416 Type SAL_CALL GlobalEventConfig::getElementType(  ) throw (RuntimeException)
417 {
418     MutexGuard aGuard( GetOwnStaticMutex() );
419     return m_pImpl->getElementType( );
420 }
421 sal_Bool SAL_CALL GlobalEventConfig::hasElements(  ) throw (RuntimeException)
422 {
423     MutexGuard aGuard( GetOwnStaticMutex() );
424     return m_pImpl->hasElements( );
425 }
426 
427 Mutex& GlobalEventConfig::GetOwnStaticMutex()
428 {
429 	// Initialize static mutex only for one time!
430     static Mutex* pMutex = NULL;
431 	// If these method first called (Mutex not already exist!) ...
432     if( pMutex == NULL )
433     {
434 		// ... we must create a new one. Protect following code with
435         // the global mutex -
436 		// It must be - we create a static variable!
437         MutexGuard aGuard( Mutex::getGlobalMutex() );
438 		// We must check our pointer again - because it can be that
439         // another instance of our class will be faster then these!
440         if( pMutex == NULL )
441         {
442 			// Create the new mutex and set it for return on static variable.
443             static Mutex aMutex;
444             pMutex = &aMutex;
445         }
446     }
447 	// Return new created or already existing mutex object.
448     return *pMutex;
449 }
450 
451 ::rtl::OUString GlobalEventConfig::GetEventName( sal_Int32 nIndex )
452 {
453 	return GlobalEventConfig().m_pImpl->GetEventName( nIndex );
454 }
455 
456