1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_dbaccess.hxx"
26 
27 #include "documenteventexecutor.hxx"
28 
29 /** === begin UNO includes === **/
30 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
31 #include <com/sun/star/util/XURLTransformer.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/XDispatchProvider.hpp>
34 /** === end UNO includes === **/
35 
36 #include <comphelper/componentcontext.hxx>
37 #include <comphelper/namedvaluecollection.hxx>
38 #include <cppuhelper/weakref.hxx>
39 #include <tools/diagnose_ex.h>
40 #include <vcl/svapp.hxx>
41 #include <vos/mutex.hxx>
42 
43 //........................................................................
44 namespace dbaccess
45 {
46 //........................................................................
47 
48     /** === begin UNO using === **/
49     using ::com::sun::star::uno::Reference;
50     using ::com::sun::star::uno::XInterface;
51     using ::com::sun::star::uno::UNO_QUERY;
52     using ::com::sun::star::uno::UNO_QUERY_THROW;
53     using ::com::sun::star::uno::UNO_SET_THROW;
54     using ::com::sun::star::uno::Exception;
55     using ::com::sun::star::uno::RuntimeException;
56     using ::com::sun::star::uno::Any;
57     using ::com::sun::star::uno::makeAny;
58     using ::com::sun::star::uno::Sequence;
59     using ::com::sun::star::uno::Type;
60     using ::com::sun::star::uno::WeakReference;
61     using ::com::sun::star::document::XDocumentEventBroadcaster;
62     using ::com::sun::star::document::XEventsSupplier;
63     using ::com::sun::star::container::XNameAccess;
64     using ::com::sun::star::frame::XModel;
65     using ::com::sun::star::util::XURLTransformer;
66     using ::com::sun::star::frame::XDispatchProvider;
67     using ::com::sun::star::frame::XDispatch;
68     using ::com::sun::star::util::URL;
69     using ::com::sun::star::beans::PropertyValue;
70     using ::com::sun::star::frame::XController;
71     using ::com::sun::star::document::DocumentEvent;
72     /** === end UNO using === **/
73     using namespace ::com::sun::star;
74 
75     //====================================================================
76     //= DocumentEventExecutor_Data
77     //====================================================================
78     struct DocumentEventExecutor_Data
79     {
80         WeakReference< XEventsSupplier >    xDocument;
81         Reference< XURLTransformer >        xURLTransformer;
82 
DocumentEventExecutor_Datadbaccess::DocumentEventExecutor_Data83         DocumentEventExecutor_Data( const Reference< XEventsSupplier >& _rxDocument )
84             :xDocument( _rxDocument )
85         {
86         }
87     };
88 
89     //--------------------------------------------------------------------
90     namespace
91     {
lcl_dispatchScriptURL_throw(DocumentEventExecutor_Data & _rDocExecData,const::rtl::OUString & _rScriptURL,const DocumentEvent & _rTrigger)92         static void lcl_dispatchScriptURL_throw( DocumentEventExecutor_Data& _rDocExecData,
93             const ::rtl::OUString& _rScriptURL, const DocumentEvent& _rTrigger )
94         {
95             Reference< XModel > xDocument( _rDocExecData.xDocument.get(), UNO_QUERY_THROW );
96 
97             Reference< XController > xController( xDocument->getCurrentController() );
98             Reference< XDispatchProvider > xDispProv;
99             if ( xController.is() )
100                 xDispProv.set( xController->getFrame(), UNO_QUERY );
101             if ( !xDispProv.is() )
102             {
103                 OSL_ENSURE( false, "lcl_dispatchScriptURL_throw: no controller/frame? How should I dispatch?" );
104                 return;
105             }
106 
107             URL aScriptURL;
108             aScriptURL.Complete = _rScriptURL;
109             if ( _rDocExecData.xURLTransformer.is() )
110                 _rDocExecData.xURLTransformer->parseStrict( aScriptURL );
111 
112             // unfortunately, executing a script can trigger all kind of complex stuff, and unfortunately, not
113             // every component involved into this properly cares for thread safety. To be on the safe side,
114             // we lock the solar mutex here.
115             ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
116 
117             Reference< XDispatch > xDispatch( xDispProv->queryDispatch( aScriptURL, ::rtl::OUString(), 0 ) );
118             if ( !xDispatch.is() )
119             {
120                 OSL_ENSURE( false, "lcl_dispatchScriptURL_throw: no dispatcher for the script URL!" );
121                 return;
122             }
123 
124             PropertyValue aEventParam;
125             aEventParam.Value <<= _rTrigger;
126             Sequence< PropertyValue > aDispatchArgs( &aEventParam, 1 );
127             xDispatch->dispatch( aScriptURL, aDispatchArgs );
128         }
129     }
130 
131     //====================================================================
132     //= DocumentEventExecutor
133     //====================================================================
134     //--------------------------------------------------------------------
DocumentEventExecutor(const::comphelper::ComponentContext & _rContext,const Reference<XEventsSupplier> & _rxDocument)135     DocumentEventExecutor::DocumentEventExecutor( const ::comphelper::ComponentContext& _rContext,
136             const Reference< XEventsSupplier >& _rxDocument )
137         :m_pData( new DocumentEventExecutor_Data( _rxDocument ) )
138     {
139         Reference< XDocumentEventBroadcaster > xBroadcaster( _rxDocument, UNO_QUERY_THROW );
140 
141         osl_incrementInterlockedCount( &m_refCount );
142         {
143             xBroadcaster->addDocumentEventListener( this );
144         }
145         osl_decrementInterlockedCount( &m_refCount );
146 
147         try
148         {
149             _rContext.createComponent( "com.sun.star.util.URLTransformer", m_pData->xURLTransformer );
150         }
151         catch( const Exception& )
152         {
153         	DBG_UNHANDLED_EXCEPTION();
154         }
155     }
156 
157     //--------------------------------------------------------------------
~DocumentEventExecutor()158     DocumentEventExecutor::~DocumentEventExecutor()
159     {
160     }
161 
162     //--------------------------------------------------------------------
documentEventOccured(const DocumentEvent & _Event)163     void SAL_CALL DocumentEventExecutor::documentEventOccured( const DocumentEvent& _Event ) throw (RuntimeException)
164     {
165         Reference< XEventsSupplier > xEventsSupplier( m_pData->xDocument.get(), UNO_QUERY );
166         if ( !xEventsSupplier.is() )
167         {
168             OSL_ENSURE( false, "DocumentEventExecutor::documentEventOccured: no document anymore, but still being notified?" );
169             return;
170         }
171 
172         Reference< XModel > xDocument( xEventsSupplier, UNO_QUERY_THROW );
173 
174         try
175         {
176             Reference< XNameAccess > xDocEvents( xEventsSupplier->getEvents().get(), UNO_SET_THROW );
177             if ( !xDocEvents->hasByName( _Event.EventName ) )
178             {
179                 // this is worth an assertion: We are listener at the very same document which we just asked
180                 // for its events. So when EventName is fired, why isn't it supported by xDocEvents?
181                 OSL_ENSURE( false, "DocumentEventExecutor::documentEventOccured: an unsupported event is notified!" );
182                 return;
183             }
184 
185             const ::comphelper::NamedValueCollection aScriptDescriptor( xDocEvents->getByName( _Event.EventName ) );
186 
187 
188             ::rtl::OUString sEventType;
189             bool bScriptAssigned = aScriptDescriptor.get_ensureType( "EventType", sEventType );
190 
191             ::rtl::OUString sScript;
192             bScriptAssigned = bScriptAssigned && aScriptDescriptor.get_ensureType( "Script", sScript );
193 
194             if ( !bScriptAssigned )
195                 // no script is assigned to this event
196                 return;
197 
198             bool bDispatchScriptURL =
199                 (   sEventType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Script" ) )
200                 ||  sEventType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Service" ) )
201                 );
202             bool bNonEmptyScript = sScript.getLength() != 0;
203 
204             OSL_ENSURE( bDispatchScriptURL && bNonEmptyScript,
205                 "DocumentEventExecutor::documentEventOccured: invalid/unsupported script descriptor" );
206 
207             if ( bDispatchScriptURL && bNonEmptyScript )
208             {
209                 lcl_dispatchScriptURL_throw( *m_pData, sScript, _Event );
210             }
211         }
212         catch( const RuntimeException& ) { throw; }
213         catch( const Exception& )
214         {
215         	DBG_UNHANDLED_EXCEPTION();
216         }
217     }
218 
219     //--------------------------------------------------------------------
disposing(const lang::EventObject &)220     void SAL_CALL DocumentEventExecutor::disposing( const lang::EventObject& /*_Source*/ ) throw (RuntimeException)
221     {
222         // not interested in
223     }
224 
225 
226 //........................................................................
227 } // namespace dbaccess
228 //........................................................................
229