1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25 ************************************************************************/
26 
27 // MARKER(update_precomp.py): autogen include statement, do not remove
28 #include "precompiled_dbaccess.hxx"
29 
30 #include "documentevents.hxx"
31 
32 /** === begin UNO includes === **/
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 /** === end UNO includes === **/
35 
36 #include <comphelper/namedvaluecollection.hxx>
37 
38 #include <algorithm>
39 #include <functional>
40 
41 //........................................................................
42 namespace dbaccess
43 {
44 //........................................................................
45 
46     /** === begin UNO using === **/
47     using ::com::sun::star::uno::Reference;
48     using ::com::sun::star::uno::XInterface;
49     using ::com::sun::star::uno::UNO_QUERY;
50     using ::com::sun::star::uno::UNO_QUERY_THROW;
51     using ::com::sun::star::uno::UNO_SET_THROW;
52     using ::com::sun::star::uno::Exception;
53     using ::com::sun::star::uno::RuntimeException;
54     using ::com::sun::star::uno::Any;
55     using ::com::sun::star::uno::makeAny;
56     using ::com::sun::star::beans::PropertyValue;
57     using ::com::sun::star::container::NoSuchElementException;
58     using ::com::sun::star::lang::WrappedTargetException;
59     using ::com::sun::star::lang::IllegalArgumentException;
60     using ::com::sun::star::uno::Sequence;
61     using ::com::sun::star::uno::Type;
62     /** === end UNO using === **/
63 
64     //====================================================================
65     //= DocumentEvents_Data
66     //====================================================================
67     struct DocumentEvents_Data : public ::boost::noncopyable
68     {
69         ::cppu::OWeakObject&    rParent;
70         ::osl::Mutex&           rMutex;
71         DocumentEventsData&     rEventsData;
72 
73         DocumentEvents_Data( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData )
74             :rParent( _rParent )
75             ,rMutex( _rMutex )
76             ,rEventsData( _rEventsData )
77         {
78         }
79     };
80 
81     //====================================================================
82     //= helper
83     //====================================================================
84     struct DocumentEventData
85     {
86         const sal_Char* pAsciiEventName;
87         bool            bNeedsSyncNotify;
88     };
89 
90     //--------------------------------------------------------------------
91     namespace
92     {
93         static const DocumentEventData* lcl_getDocumentEventData()
94         {
95             static const DocumentEventData s_aData[] = {
96                 { "OnCreate",               true  },
97                 { "OnLoadFinished",         true  },
98                 { "OnNew",                  false },    // compatibility, see http://www.openoffice.org/issues/show_bug.cgi?id=46484
99                 { "OnLoad",                 false },    // compatibility, see http://www.openoffice.org/issues/show_bug.cgi?id=46484
100                 { "OnSaveAs",               true  },
101                 { "OnSaveAsDone",           false },
102                 { "OnSaveAsFailed",         false },
103                 { "OnSave",                 true  },
104                 { "OnSaveDone",             false },
105                 { "OnSaveFailed",           false },
106                 { "OnSaveTo",               true  },
107                 { "OnSaveToDone",           false },
108                 { "OnSaveToFailed",         false },
109                 { "OnPrepareUnload",        true  },
110                 { "OnUnload",               true  },
111                 { "OnFocus",                false },
112                 { "OnUnfocus",              false },
113                 { "OnModifyChanged",        false },
114                 { "OnViewCreated",          false },
115                 { "OnPrepareViewClosing",   true  },
116                 { "OnViewClosed",           false },
117                 { "OnTitleChanged",         false },
118                 { "OnSubComponentOpened",   false },
119                 { "OnSubComponentClosed",   false },
120                 { NULL, false }
121             };
122             return s_aData;
123         }
124     }
125 
126     //====================================================================
127     //= DocumentEvents
128     //====================================================================
129     //--------------------------------------------------------------------
130     DocumentEvents::DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData )
131         :m_pData( new DocumentEvents_Data( _rParent, _rMutex, _rEventsData ) )
132     {
133         const DocumentEventData* pEventData = lcl_getDocumentEventData();
134         while ( pEventData->pAsciiEventName )
135         {
136             ::rtl::OUString sEventName = ::rtl::OUString::createFromAscii( pEventData->pAsciiEventName );
137             DocumentEventsData::iterator existingPos = m_pData->rEventsData.find( sEventName );
138             if ( existingPos == m_pData->rEventsData.end() )
139                 m_pData->rEventsData[ sEventName ] = Sequence< PropertyValue >();
140             ++pEventData;
141         }
142     }
143 
144     //--------------------------------------------------------------------
145     DocumentEvents::~DocumentEvents()
146     {
147     }
148 
149     //--------------------------------------------------------------------
150     void SAL_CALL DocumentEvents::acquire() throw()
151     {
152         m_pData->rParent.acquire();
153     }
154 
155     //--------------------------------------------------------------------
156     void SAL_CALL DocumentEvents::release() throw()
157     {
158         m_pData->rParent.release();
159     }
160 
161     //--------------------------------------------------------------------
162     bool DocumentEvents::needsSynchronousNotification( const ::rtl::OUString& _rEventName )
163     {
164         const DocumentEventData* pEventData = lcl_getDocumentEventData();
165         while ( pEventData->pAsciiEventName )
166         {
167             if ( _rEventName.compareToAscii( pEventData->pAsciiEventName ) == 0 )
168                 return pEventData->bNeedsSyncNotify;
169             ++pEventData;
170         }
171 
172         // this is an unknown event ... assume async notification
173         return false;
174     }
175 
176     //--------------------------------------------------------------------
177     void SAL_CALL DocumentEvents::replaceByName( const ::rtl::OUString& _Name, const Any& _Element ) throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
178     {
179         ::osl::MutexGuard aGuard( m_pData->rMutex );
180 
181         DocumentEventsData::iterator elementPos = m_pData->rEventsData.find( _Name );
182         if ( elementPos == m_pData->rEventsData.end() )
183             throw NoSuchElementException( _Name, *this );
184 
185         Sequence< PropertyValue > aEventDescriptor;
186         if ( _Element.hasValue() && !( _Element >>= aEventDescriptor ) )
187             throw IllegalArgumentException( _Element.getValueTypeName(), *this, 2 );
188 
189         // Weird enough, the event assignment UI has (well: had) the idea of using an empty "EventType"/"Script"
190         // to indicate the event descriptor should be reset, instead of just passing an empty event descriptor.
191         ::comphelper::NamedValueCollection aCheck( aEventDescriptor );
192         if ( aCheck.has( "EventType" ) )
193         {
194             ::rtl::OUString sEventType = aCheck.getOrDefault( "EventType", ::rtl::OUString() );
195             OSL_ENSURE( sEventType.getLength(), "DocumentEvents::replaceByName: doing a reset via an empty EventType is weird!" );
196             if ( !sEventType.getLength() )
197                 aEventDescriptor.realloc( 0 );
198         }
199         if ( aCheck.has( "Script" ) )
200         {
201             ::rtl::OUString sScript = aCheck.getOrDefault( "Script", ::rtl::OUString() );
202             OSL_ENSURE( sScript.getLength(), "DocumentEvents::replaceByName: doing a reset via an empty Script is weird!" );
203             if ( !sScript.getLength() )
204                 aEventDescriptor.realloc( 0 );
205         }
206 
207         elementPos->second = aEventDescriptor;
208     }
209 
210     //--------------------------------------------------------------------
211     Any SAL_CALL DocumentEvents::getByName( const ::rtl::OUString& _Name ) throw (NoSuchElementException, WrappedTargetException, RuntimeException)
212     {
213         ::osl::MutexGuard aGuard( m_pData->rMutex );
214 
215         DocumentEventsData::const_iterator elementPos = m_pData->rEventsData.find( _Name );
216         if ( elementPos == m_pData->rEventsData.end() )
217             throw NoSuchElementException( _Name, *this );
218 
219         Any aReturn;
220         const Sequence< PropertyValue >& rEventDesc( elementPos->second );
221         if ( rEventDesc.getLength() > 0 )
222             aReturn <<= rEventDesc;
223         return aReturn;
224     }
225 
226     //--------------------------------------------------------------------
227     Sequence< ::rtl::OUString > SAL_CALL DocumentEvents::getElementNames(  ) throw (RuntimeException)
228     {
229         ::osl::MutexGuard aGuard( m_pData->rMutex );
230 
231         Sequence< ::rtl::OUString > aNames( m_pData->rEventsData.size() );
232         ::std::transform(
233             m_pData->rEventsData.begin(),
234             m_pData->rEventsData.end(),
235             aNames.getArray(),
236             ::std::select1st< DocumentEventsData::value_type >()
237         );
238         return aNames;
239     }
240 
241     //--------------------------------------------------------------------
242     ::sal_Bool SAL_CALL DocumentEvents::hasByName( const ::rtl::OUString& _Name ) throw (RuntimeException)
243     {
244         ::osl::MutexGuard aGuard( m_pData->rMutex );
245 
246         return m_pData->rEventsData.find( _Name ) != m_pData->rEventsData.end();
247     }
248 
249     //--------------------------------------------------------------------
250     Type SAL_CALL DocumentEvents::getElementType(  ) throw (RuntimeException)
251     {
252         return ::cppu::UnoType< Sequence< PropertyValue > >::get();
253     }
254 
255     //--------------------------------------------------------------------
256     ::sal_Bool SAL_CALL DocumentEvents::hasElements(  ) throw (RuntimeException)
257     {
258         ::osl::MutexGuard aGuard( m_pData->rMutex );
259         return !m_pData->rEventsData.empty();
260     }
261 
262 
263 //........................................................................
264 } // namespace dbaccess
265 //........................................................................
266