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 : #include <dispatch/interceptionhelper.hxx>
21 :
22 : #include <com/sun/star/frame/XInterceptorInfo.hpp>
23 :
24 : #include <vcl/svapp.hxx>
25 :
26 :
27 : namespace framework{
28 :
29 :
30 : sal_Bool InterceptionHelper::m_bPreferrFirstInterceptor = sal_True;
31 :
32 :
33 :
34 3972 : DEFINE_XINTERFACE_3(InterceptionHelper ,
35 : OWeakObject ,
36 : DIRECT_INTERFACE(css::frame::XDispatchProvider ),
37 : DIRECT_INTERFACE(css::frame::XDispatchProviderInterception),
38 : DIRECT_INTERFACE(css::lang::XEventListener ))
39 :
40 260 : InterceptionHelper::InterceptionHelper(const css::uno::Reference< css::frame::XFrame >& xOwner,
41 : const css::uno::Reference< css::frame::XDispatchProvider >& xSlave)
42 : // Init baseclasses first
43 260 : : ThreadHelpBase(&Application::GetSolarMutex())
44 : , OWeakObject ( )
45 : // Init member
46 : , m_xOwnerWeak (xOwner )
47 520 : , m_xSlave (xSlave )
48 : {
49 260 : }
50 :
51 166 : InterceptionHelper::~InterceptionHelper()
52 : {
53 166 : }
54 :
55 3995 : css::uno::Reference< css::frame::XDispatch > SAL_CALL InterceptionHelper::queryDispatch(const css::util::URL& aURL ,
56 : const ::rtl::OUString& sTargetFrameName,
57 : sal_Int32 nSearchFlags )
58 : throw(css::uno::RuntimeException)
59 : {
60 : // SAFE {
61 3995 : ReadGuard aReadLock(m_aLock);
62 :
63 : // a) first search an interceptor, which match to this URL by it's URL pattern registration
64 : // Note: if it return NULL - it does not mean an empty interceptor list automaticly!
65 3995 : css::uno::Reference< css::frame::XDispatchProvider > xInterceptor;
66 3995 : InterceptorList::const_iterator pIt = m_lInterceptionRegs.findByPattern(aURL.Complete);
67 3995 : if (pIt != m_lInterceptionRegs.end())
68 3995 : xInterceptor = pIt->xInterceptor;
69 :
70 : // b) No match by registration - but a valid interceptor list.
71 : // Use first interceptor everytimes.
72 : // Note: it doesn't matter, which direction this helper implementation use to ask interceptor objects.
73 : // Using of member m_aInterceptorList will starts at the beginning everytimes.
74 : // It depends from the filling operation, in which direction it works realy!
75 3995 : if (!xInterceptor.is() && m_lInterceptionRegs.size()>0)
76 : {
77 0 : pIt = m_lInterceptionRegs.begin();
78 0 : xInterceptor = pIt->xInterceptor;
79 : }
80 :
81 : // c) No registered interceptor => use our direct slave.
82 : // This helper exist by design and must be valid everytimes ...
83 : // But to be more feature proof - we should check that .-)
84 3995 : if (!xInterceptor.is() && m_xSlave.is())
85 0 : xInterceptor = m_xSlave;
86 :
87 3995 : aReadLock.unlock();
88 : // } SAFE
89 :
90 3995 : css::uno::Reference< css::frame::XDispatch > xReturn;
91 3995 : if (xInterceptor.is())
92 3995 : xReturn = xInterceptor->queryDispatch(aURL, sTargetFrameName, nSearchFlags);
93 3995 : return xReturn;
94 : }
95 :
96 0 : css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL InterceptionHelper::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor )
97 : throw(css::uno::RuntimeException)
98 : {
99 0 : sal_Int32 c = lDescriptor.getLength();
100 0 : css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatches (c);
101 0 : css::uno::Reference< css::frame::XDispatch >* pDispatches = lDispatches.getArray();
102 0 : const css::frame::DispatchDescriptor* pDescriptor = lDescriptor.getConstArray();
103 :
104 0 : for (sal_Int32 i=0; i<c; ++i)
105 0 : pDispatches[i] = queryDispatch(pDescriptor[i].FeatureURL, pDescriptor[i].FrameName, pDescriptor[i].SearchFlags);
106 :
107 0 : return lDispatches;
108 : }
109 :
110 236 : void SAL_CALL InterceptionHelper::registerDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
111 : throw(css::uno::RuntimeException)
112 : {
113 : // reject wrong calling of this interface method
114 236 : css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
115 236 : if (!xInterceptor.is())
116 0 : throw css::uno::RuntimeException(DECLARE_ASCII("NULL references not allowed as in parameter"), xThis);
117 :
118 : // Fill a new info structure for new interceptor.
119 : // Save his reference and try to get an additional URL/pattern list from him.
120 : // If no list exist register these interceptor for all dispatch events with "*"!
121 236 : InterceptorInfo aInfo;
122 :
123 236 : aInfo.xInterceptor = css::uno::Reference< css::frame::XDispatchProvider >(xInterceptor, css::uno::UNO_QUERY);
124 236 : css::uno::Reference< css::frame::XInterceptorInfo > xInfo(xInterceptor, css::uno::UNO_QUERY);
125 236 : if (xInfo.is())
126 0 : aInfo.lURLPattern = xInfo->getInterceptedURLs();
127 : else
128 : {
129 236 : aInfo.lURLPattern.realloc(1);
130 236 : aInfo.lURLPattern[0] = ::rtl::OUString("*");
131 : }
132 :
133 : // SAFE {
134 236 : WriteGuard aWriteLock(m_aLock);
135 :
136 : // a) no interceptor at all - set this instance as master for given interceptor
137 : // and set our slave as it's slave - and put this interceptor to the list.
138 : // It's place there doesn matter. Because this list is currently empty.
139 236 : if (m_lInterceptionRegs.empty())
140 : {
141 236 : xInterceptor->setMasterDispatchProvider(xThis );
142 236 : xInterceptor->setSlaveDispatchProvider (m_xSlave);
143 236 : m_lInterceptionRegs.push_back(aInfo);
144 : }
145 :
146 : // b) OK - there is at least one interceptor already registered.
147 : // It's slave and it's master must be valid references ...
148 : // because we created it. But we have to look for the static bool which
149 : // regulate direction of using of interceptor objects!
150 :
151 : // b1) If "m_bPreferrFirstInterceptor" is set to true, we have to
152 : // insert it behind any other existing interceptor - means at the end of our list.
153 0 : else if (m_bPreferrFirstInterceptor)
154 : {
155 0 : css::uno::Reference< css::frame::XDispatchProvider > xMasterD = m_lInterceptionRegs.rbegin()->xInterceptor;
156 0 : css::uno::Reference< css::frame::XDispatchProviderInterceptor > xMasterI (xMasterD, css::uno::UNO_QUERY);
157 :
158 0 : xInterceptor->setMasterDispatchProvider(xMasterD );
159 0 : xInterceptor->setSlaveDispatchProvider (m_xSlave );
160 0 : xMasterI->setSlaveDispatchProvider (aInfo.xInterceptor);
161 :
162 0 : m_lInterceptionRegs.push_back(aInfo);
163 : }
164 :
165 : // b2) If "m_bPreferrFirstInterceptor" is set to false, we have to
166 : // insert it before any other existing interceptor - means at the beginning of our list.
167 : else
168 : {
169 0 : css::uno::Reference< css::frame::XDispatchProvider > xSlaveD = m_lInterceptionRegs.begin()->xInterceptor;
170 0 : css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY);
171 :
172 0 : xInterceptor->setMasterDispatchProvider(xThis );
173 0 : xInterceptor->setSlaveDispatchProvider (xSlaveD );
174 0 : xSlaveI->setMasterDispatchProvider (aInfo.xInterceptor);
175 :
176 0 : m_lInterceptionRegs.push_front(aInfo);
177 : }
178 :
179 236 : css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY);
180 :
181 236 : aWriteLock.unlock();
182 : // } SAFE
183 :
184 : // Don't forget to send a frame action event "context changed".
185 : // Any cached dispatch objects must be validated now!
186 236 : if (xOwner.is())
187 236 : xOwner->contextChanged();
188 236 : }
189 :
190 63 : void SAL_CALL InterceptionHelper::releaseDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor)
191 : throw(css::uno::RuntimeException)
192 : {
193 : // reject wrong calling of this interface method
194 63 : css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
195 63 : if (!xInterceptor.is())
196 0 : throw css::uno::RuntimeException(DECLARE_ASCII("NULL references not allowed as in parameter"), xThis);
197 :
198 : // SAFE {
199 63 : WriteGuard aWriteLock(m_aLock);
200 :
201 : // search this interceptor ...
202 : // If it could be located inside cache -
203 : // use it's slave/master relations to update the interception list;
204 : // set empty references for it as new master and slave;
205 : // and relase it from out cache.
206 63 : InterceptorList::iterator pIt = m_lInterceptionRegs.findByReference(xInterceptor);
207 63 : if (pIt != m_lInterceptionRegs.end())
208 : {
209 63 : css::uno::Reference< css::frame::XDispatchProvider > xSlaveD (xInterceptor->getSlaveDispatchProvider() , css::uno::UNO_QUERY);
210 63 : css::uno::Reference< css::frame::XDispatchProvider > xMasterD (xInterceptor->getMasterDispatchProvider(), css::uno::UNO_QUERY);
211 63 : css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY);
212 63 : css::uno::Reference< css::frame::XDispatchProviderInterceptor > xMasterI (xMasterD , css::uno::UNO_QUERY);
213 :
214 63 : if (xMasterI.is())
215 0 : xMasterI->setSlaveDispatchProvider(xSlaveD);
216 :
217 63 : if (xSlaveI.is())
218 0 : xSlaveI->setMasterDispatchProvider(xMasterD);
219 :
220 63 : xInterceptor->setSlaveDispatchProvider (css::uno::Reference< css::frame::XDispatchProvider >());
221 63 : xInterceptor->setMasterDispatchProvider(css::uno::Reference< css::frame::XDispatchProvider >());
222 :
223 63 : m_lInterceptionRegs.erase(pIt);
224 : }
225 :
226 63 : css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY);
227 :
228 63 : aWriteLock.unlock();
229 : // } SAFE
230 :
231 : // Don't forget to send a frame action event "context changed".
232 : // Any cached dispatch objects must be validated now!
233 63 : if (xOwner.is())
234 63 : xOwner->contextChanged();
235 63 : }
236 :
237 : #define FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN
238 63 : void SAL_CALL InterceptionHelper::disposing(const css::lang::EventObject& aEvent)
239 : throw(css::uno::RuntimeException)
240 : {
241 : #ifdef FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN
242 : // SAFE ->
243 63 : ReadGuard aReadLock(m_aLock);
244 :
245 : // check calli ... we accept such disposing call's only from our onwer frame.
246 63 : css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY);
247 63 : if (aEvent.Source != xOwner)
248 63 : return;
249 :
250 : // Because every interceptor hold at least one reference to us ... and we destruct this list
251 : // of interception objects ... we should hold ourself alive .-)
252 63 : css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY_THROW);
253 :
254 : // We need a full copy of all currently registered interceptor objects.
255 : // Otherwhise we cant iterate over this vector without the risk, that our iterator will be invalid.
256 : // Because this vetor will be influenced by every deregistered interceptor.
257 63 : InterceptionHelper::InterceptorList aCopy = m_lInterceptionRegs;
258 :
259 63 : aReadLock.unlock();
260 : // <- SAFE
261 :
262 63 : InterceptionHelper::InterceptorList::iterator pIt;
263 189 : for ( pIt = aCopy.begin();
264 126 : pIt != aCopy.end() ;
265 : ++pIt )
266 : {
267 0 : InterceptionHelper::InterceptorInfo& rInfo = *pIt;
268 0 : if (rInfo.xInterceptor.is())
269 : {
270 0 : css::uno::Reference< css::frame::XDispatchProviderInterceptor > xInterceptor(rInfo.xInterceptor, css::uno::UNO_QUERY_THROW);
271 0 : releaseDispatchProviderInterceptor(xInterceptor);
272 0 : rInfo.xInterceptor.clear();
273 : }
274 : }
275 :
276 63 : aCopy.clear();
277 :
278 : #if OSL_DEBUG_LEVEL > 0
279 : // SAFE ->
280 : aReadLock.lock();
281 : if (!m_lInterceptionRegs.empty() )
282 : OSL_FAIL("There are some pending interceptor objects, which seams to be registered during (!) the destruction of a frame.");
283 : aReadLock.unlock();
284 : // <- SAFE
285 : #endif // ODL_DEBUG_LEVEL>0
286 :
287 : #endif // FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN
288 : }
289 :
290 : } // namespace framework
291 :
292 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|