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 #ifndef INCLUDED_VBAHELPER_VBAEVENTSHELPERBASE_HXX
21 #define INCLUDED_VBAHELPER_VBAEVENTSHELPERBASE_HXX
22 
23 #include <deque>
24 #include <map>
25 #include <unordered_map>
26 
27 #include <com/sun/star/document/XEventListener.hpp>
28 #include <com/sun/star/lang/EventObject.hpp>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/lang/IllegalArgumentException.hpp>
31 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
32 #include <com/sun/star/uno/Any.hxx>
33 #include <com/sun/star/uno/Reference.hxx>
34 #include <com/sun/star/uno/Sequence.hxx>
35 #include <com/sun/star/util/XChangesListener.hpp>
36 #include <cppuhelper/implbase.hxx>
37 #include <rtl/ustring.hxx>
38 #include <sal/types.h>
39 #include <vbahelper/vbadllapi.h>
40 
41 namespace com::sun::star {
42     namespace document { struct EventObject; }
43     namespace frame { class XModel; }
44     namespace script::vba { class XVBAModuleInfo; }
45     namespace uno { class XComponentContext; }
46     namespace util { struct ChangesEvent; }
47 }
48 
49 class SfxObjectShell;
50 
51 typedef ::cppu::WeakImplHelper<
52     css::script::vba::XVBAEventProcessor,
53     css::document::XEventListener,
54     css::util::XChangesListener,
55     css::lang::XServiceInfo > VbaEventsHelperBase_BASE;
56 
57 class VBAHELPER_DLLPUBLIC VbaEventsHelperBase : public VbaEventsHelperBase_BASE
58 {
59 public:
60     VbaEventsHelperBase(
61         const css::uno::Sequence< css::uno::Any >& rArgs );
62     virtual ~VbaEventsHelperBase() override;
63 
64     // script::vba::XVBAEventProcessor
65     virtual sal_Bool SAL_CALL hasVbaEventHandler( sal_Int32 nEventId, const css::uno::Sequence< css::uno::Any >& rArgs ) override;
66     virtual sal_Bool SAL_CALL processVbaEvent( sal_Int32 nEventId, const css::uno::Sequence< css::uno::Any >& rArgs ) override;
67 
68     // document::XEventListener
69     virtual void SAL_CALL notifyEvent( const css::document::EventObject& rEvent ) override;
70 
71     // util::XChangesListener
72     virtual void SAL_CALL changesOccurred( const css::util::ChangesEvent& rEvent ) override;
73 
74     // lang::XEventListener
75     virtual void SAL_CALL disposing( const css::lang::EventObject& rEvent ) override;
76 
77     sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
78 
79     // little helpers ---------------------------------------------------------
80 
81     /** Helper to execute event handlers without throwing any exceptions. */
82     void processVbaEventNoThrow( sal_Int32 nEventId, const css::uno::Sequence< css::uno::Any >& rArgs );
83 
84     /** @throws css::lang::IllegalArgumentException if the passed sequence does not contain a value at the specified index. */
checkArgument(const css::uno::Sequence<css::uno::Any> & rArgs,sal_Int32 nIndex)85     static void checkArgument( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex )
86         { if( (nIndex < 0) || (nIndex >= rArgs.getLength()) ) throw css::lang::IllegalArgumentException(); }
87 
88     /** @throws css::lang::IllegalArgumentException if the passed sequence does not contain a value of a specific at the specified index. */
89     template< typename Type >
checkArgumentType(const css::uno::Sequence<css::uno::Any> & rArgs,sal_Int32 nIndex)90     static void checkArgumentType( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex )
91         { checkArgument( rArgs, nIndex ); if( !rArgs[ nIndex ].has< Type >() ) throw css::lang::IllegalArgumentException(); }
92 
93 protected:
94 
95 
96     struct EventHandlerInfo
97     {
98         sal_Int32 mnEventId;
99         sal_Int32 mnModuleType;
100         OUString maMacroName;
101         sal_Int32 mnCancelIndex;
102         css::uno::Any maUserData;
103     };
104 
105     /** Registers a supported event handler.
106 
107         @param nEventId  Event identifier from com.sun.star.script.vba.VBAEventId.
108         @param nModuleType  Type of the module containing the event handler.
109         @param pcMacroName  Name of the associated VBA event handler macro.
110         @param nCancelIndex  0-based index of Cancel parameter, or -1.
111         @param rUserData  User data for free usage in derived implementations. */
112     void registerEventHandler(
113             sal_Int32 nEventId,
114             sal_Int32 nModuleType,
115             const char* pcMacroName,
116             sal_Int32 nCancelIndex = -1,
117             const css::uno::Any& rUserData = css::uno::Any() );
118 
119 
120     struct EventQueueEntry
121     {
122         sal_Int32 mnEventId;
123         css::uno::Sequence< css::uno::Any > maArgs;
EventQueueEntryVbaEventsHelperBase::EventQueueEntry124         /*implicit*/ EventQueueEntry( sal_Int32 nEventId ) : mnEventId( nEventId ) {}
EventQueueEntryVbaEventsHelperBase::EventQueueEntry125         EventQueueEntry( sal_Int32 nEventId, const css::uno::Sequence< css::uno::Any >& rArgs ) : mnEventId( nEventId ), maArgs( rArgs ) {}
126     };
127     typedef ::std::deque< EventQueueEntry > EventQueue;
128 
129     /** Derived classes do additional preparations and return whether the
130         event handler has to be called.
131 
132         @throws css::uno::RuntimeException
133     */
134     virtual bool implPrepareEvent(
135         EventQueue& rEventQueue,
136         const EventHandlerInfo& rInfo,
137         const css::uno::Sequence< css::uno::Any >& rArgs ) = 0;
138 
139     /** Derived classes have to return the argument list for the specified VBA event handler.
140 
141         @throws css::lang::IllegalArgumentException
142         @throws css::uno::RuntimeException
143     */
144     virtual css::uno::Sequence< css::uno::Any > implBuildArgumentList(
145         const EventHandlerInfo& rInfo,
146         const css::uno::Sequence< css::uno::Any >& rArgs ) = 0;
147 
148     /** Derived classes may do additional postprocessing. Called even if the
149         event handler does not exist, or if an error occurred during execution.
150 
151         @throws css::uno::RuntimeException
152     */
153     virtual void implPostProcessEvent(
154         EventQueue& rEventQueue,
155         const EventHandlerInfo& rInfo,
156         bool bCancel ) = 0;
157 
158     /** Derived classes have to return the name of the Basic document module.
159 
160         @throws css::lang::IllegalArgumentException
161         @throws css::uno::RuntimeException
162     */
163     virtual OUString implGetDocumentModuleName(
164         const EventHandlerInfo& rInfo,
165         const css::uno::Sequence< css::uno::Any >& rArgs ) const = 0;
166 
167 private:
168     typedef ::std::map< sal_Int32, OUString > ModulePathMap;
169 
170     /** Starts listening at the document model. */
171     void startListening();
172     /** Stops listening at the document model. */
173     void stopListening();
174 
175     /** Returns the event handler info struct for the specified event, or throws.
176 
177 
178         @throws css::lang::IllegalArgumentException
179     */
180     const EventHandlerInfo& getEventHandlerInfo( sal_Int32 nEventId ) const;
181 
182     /** Searches the event handler in the document and returns its full script path.
183 
184 
185         @throws css::lang::IllegalArgumentException
186         @throws css::uno::RuntimeException
187     */
188     OUString getEventHandlerPath(
189         const EventHandlerInfo& rInfo,
190         const css::uno::Sequence< css::uno::Any >& rArgs );
191 
192     /** On first call, accesses the Basic library containing the VBA source code.
193 
194         @throws css::uno::RuntimeException
195     */
196     void ensureVBALibrary();
197 
198     /** Returns the type of the Basic module with the specified name.
199 
200         @throws css::uno::RuntimeException
201     */
202     sal_Int32 getModuleType( const OUString& rModuleName );
203 
204     /** Updates the map containing paths to event handlers for a Basic module.
205 
206         @throws css::uno::RuntimeException
207     */
208     ModulePathMap& updateModulePathMap( const OUString& rModuleName );
209 
210 protected:
211     css::uno::Reference< css::frame::XModel > mxModel;
212     SfxObjectShell* mpShell;
213 
214 private:
215     typedef std::map< sal_Int32, EventHandlerInfo > EventHandlerInfoMap;
216     typedef std::unordered_map< OUString, ModulePathMap > EventHandlerPathMap;
217 
218     EventHandlerInfoMap maEventInfos;
219     EventHandlerPathMap maEventPaths;
220     css::uno::Reference< css::script::vba::XVBAModuleInfo > mxModuleInfos;
221     OUString maLibraryName;
222     bool mbDisposed;
223 };
224 
225 
226 #endif
227 
228 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
229