/src/libreoffice/framework/source/dispatch/interceptionhelper.cxx
Line | Count | Source |
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/dispatchprovider.hxx> |
21 | | #include <dispatch/interceptionhelper.hxx> |
22 | | |
23 | | #include <com/sun/star/frame/XInterceptorInfo.hpp> |
24 | | #include <com/sun/star/lang/DisposedException.hpp> |
25 | | #include <osl/diagnose.h> |
26 | | #include <utility> |
27 | | #include <vcl/svapp.hxx> |
28 | | #include <comphelper/diagnose_ex.hxx> |
29 | | |
30 | | using namespace com::sun::star; |
31 | | |
32 | | namespace framework{ |
33 | | |
34 | | InterceptionHelper::InterceptionHelper(const css::uno::Reference< css::frame::XFrame >& xOwner, |
35 | | rtl::Reference< DispatchProvider > xSlave) |
36 | 7.17k | : m_xOwnerWeak (xOwner ) |
37 | 7.17k | , m_xSlave (std::move(xSlave )) |
38 | 7.17k | { |
39 | 7.17k | } |
40 | | |
41 | | InterceptionHelper::~InterceptionHelper() |
42 | 3.28k | { |
43 | 3.28k | } |
44 | | |
45 | | css::uno::Reference< css::frame::XDispatch > SAL_CALL InterceptionHelper::queryDispatch(const css::util::URL& aURL , |
46 | | const OUString& sTargetFrameName, |
47 | | sal_Int32 nSearchFlags ) |
48 | 0 | { |
49 | 0 | css::uno::Reference<css::frame::XDispatchProvider> xInterceptor; |
50 | | // SAFE { |
51 | 0 | { |
52 | 0 | SolarMutexGuard aReadLock; |
53 | | |
54 | | // a) first search an interceptor, which match to this URL by its URL pattern registration |
55 | | // Note: if it return NULL - it does not mean an empty interceptor list automatically! |
56 | 0 | InterceptorList::const_iterator pIt = m_lInterceptionRegs.findByPattern(aURL.Complete); |
57 | 0 | if (pIt != m_lInterceptionRegs.end()) |
58 | 0 | xInterceptor = pIt->xInterceptor; |
59 | | |
60 | | // b) No match by registration - but a valid interceptor list. |
61 | | // Find first interceptor w/o pattern, so we need to query it |
62 | 0 | if (!xInterceptor.is()) |
63 | 0 | { |
64 | 0 | for (auto const& lInterceptionReg : m_lInterceptionRegs) |
65 | 0 | { |
66 | 0 | if (!lInterceptionReg.lURLPattern.hasElements()) |
67 | 0 | { |
68 | | // no pattern -> need to ask this guy! |
69 | 0 | xInterceptor = lInterceptionReg.xInterceptor; |
70 | 0 | break; |
71 | 0 | } |
72 | 0 | } |
73 | | // if we didn't find any non-pattern interceptor, there's no-one |
74 | | // registered for this command url (we already searched for matching |
75 | | // patterns above) |
76 | 0 | } |
77 | | // c) No registered interceptor => use our direct slave. |
78 | | // This helper exist by design and must be valid everytimes ... |
79 | | // But to be more feature proof - we should check that .-) |
80 | 0 | if (!xInterceptor.is() && m_xSlave.is()) |
81 | 0 | xInterceptor = m_xSlave; |
82 | 0 | } |
83 | | // } SAFE |
84 | |
|
85 | 0 | css::uno::Reference< css::frame::XDispatch > xReturn; |
86 | 0 | if (xInterceptor.is()) |
87 | 0 | xReturn = xInterceptor->queryDispatch(aURL, sTargetFrameName, nSearchFlags); |
88 | 0 | return xReturn; |
89 | 0 | } |
90 | | |
91 | | css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL InterceptionHelper::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) |
92 | 0 | { |
93 | 0 | css::uno::Sequence<css::uno::Reference<css::frame::XDispatch>> lDispatches(lDescriptor.getLength()); |
94 | 0 | std::transform(lDescriptor.begin(), lDescriptor.end(), lDispatches.getArray(), |
95 | 0 | [this](const css::frame::DispatchDescriptor& r) |
96 | 0 | { return queryDispatch(r.FeatureURL, r.FrameName, r.SearchFlags); }); |
97 | |
|
98 | 0 | return lDispatches; |
99 | 0 | } |
100 | | |
101 | | void SAL_CALL InterceptionHelper::registerDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor) |
102 | 3.28k | { |
103 | | // reject incorrect calls of this interface method |
104 | 3.28k | css::uno::Reference< css::frame::XDispatchProvider > xThis(this); |
105 | 3.28k | if (!xInterceptor.is()) |
106 | 0 | throw css::uno::RuntimeException(u"NULL references not allowed as in parameter"_ustr, xThis); |
107 | | |
108 | | // Fill a new info structure for new interceptor. |
109 | | // Save his reference and try to get an additional URL/pattern list from him. |
110 | | // If no list exist register these interceptor for all dispatch events with "*"! |
111 | 3.28k | InterceptorInfo aInfo; |
112 | | |
113 | 3.28k | aInfo.xInterceptor = xInterceptor; |
114 | 3.28k | css::uno::Reference< css::frame::XInterceptorInfo > xInfo(xInterceptor, css::uno::UNO_QUERY); |
115 | 3.28k | if (xInfo.is()) |
116 | 3.28k | aInfo.lURLPattern = xInfo->getInterceptedURLs(); |
117 | 0 | else |
118 | 0 | aInfo.lURLPattern = { u"*"_ustr }; |
119 | | |
120 | | // SAFE { |
121 | 3.28k | SolarMutexClearableGuard aWriteLock; |
122 | | |
123 | | // a) no interceptor at all - set this instance as master for given interceptor |
124 | | // and set our slave as its slave - and put this interceptor to the list. |
125 | | // Its place there doesn't matter. Because this list is currently empty. |
126 | 3.28k | if (m_lInterceptionRegs.empty()) |
127 | 3.28k | { |
128 | 3.28k | xInterceptor->setMasterDispatchProvider(xThis ); |
129 | 3.28k | xInterceptor->setSlaveDispatchProvider (m_xSlave); |
130 | 3.28k | m_lInterceptionRegs.push_back(std::move(aInfo)); |
131 | 3.28k | } |
132 | | |
133 | | // b) OK - there is at least one interceptor already registered. |
134 | | // It's slave and it's master must be valid references ... |
135 | | // because we created it. |
136 | | |
137 | | // insert it before any other existing interceptor - means at the beginning of our list. |
138 | 0 | else |
139 | 0 | { |
140 | 0 | css::uno::Reference< css::frame::XDispatchProvider > xSlaveD = m_lInterceptionRegs.begin()->xInterceptor; |
141 | 0 | css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY); |
142 | |
|
143 | 0 | xInterceptor->setMasterDispatchProvider(xThis ); |
144 | 0 | xInterceptor->setSlaveDispatchProvider (xSlaveD ); |
145 | 0 | xSlaveI->setMasterDispatchProvider (aInfo.xInterceptor); |
146 | |
|
147 | 0 | m_lInterceptionRegs.push_front(std::move(aInfo)); |
148 | 0 | } |
149 | | |
150 | 3.28k | css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); |
151 | | |
152 | 3.28k | aWriteLock.clear(); |
153 | | // } SAFE |
154 | | |
155 | | // Don't forget to send a frame action event "context changed". |
156 | | // Any cached dispatch objects must be validated now! |
157 | 3.28k | if (xOwner.is()) |
158 | 3.28k | xOwner->contextChanged(); |
159 | 3.28k | } |
160 | | |
161 | | void SAL_CALL InterceptionHelper::releaseDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor) |
162 | 3.28k | { |
163 | | // reject wrong calling of this interface method |
164 | 3.28k | css::uno::Reference< css::frame::XDispatchProvider > xThis(this); |
165 | 3.28k | if (!xInterceptor.is()) |
166 | 0 | throw css::uno::RuntimeException(u"NULL references not allowed as in parameter"_ustr, xThis); |
167 | | |
168 | | // SAFE { |
169 | 3.28k | SolarMutexClearableGuard aWriteLock; |
170 | | |
171 | | // search this interceptor ... |
172 | | // If it could be located inside cache - |
173 | | // use its slave/master relations to update the interception list; |
174 | | // set empty references for it as new master and slave; |
175 | | // and release it from out cache. |
176 | 3.28k | InterceptorList::iterator pIt = m_lInterceptionRegs.findByReference(xInterceptor); |
177 | 3.28k | if (pIt != m_lInterceptionRegs.end()) |
178 | 3.28k | { |
179 | 3.28k | css::uno::Reference< css::frame::XDispatchProvider > xSlaveD = xInterceptor->getSlaveDispatchProvider(); |
180 | 3.28k | css::uno::Reference< css::frame::XDispatchProvider > xMasterD = xInterceptor->getMasterDispatchProvider(); |
181 | 3.28k | css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY); |
182 | 3.28k | css::uno::Reference< css::frame::XDispatchProviderInterceptor > xMasterI (xMasterD , css::uno::UNO_QUERY); |
183 | | |
184 | 3.28k | if (xMasterI.is()) |
185 | 0 | xMasterI->setSlaveDispatchProvider(xSlaveD); |
186 | | |
187 | 3.28k | if (xSlaveI.is()) |
188 | 0 | { |
189 | 0 | try |
190 | 0 | { |
191 | 0 | xSlaveI->setMasterDispatchProvider(xMasterD); |
192 | 0 | } |
193 | 0 | catch (const lang::DisposedException&) |
194 | 0 | { |
195 | 0 | TOOLS_WARN_EXCEPTION("fwk.dispatch", |
196 | 0 | "InterceptionHelper::releaseDispatchProviderInterceptor: " |
197 | 0 | "xSlaveI is disposed: "); |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | 3.28k | xInterceptor->setSlaveDispatchProvider (css::uno::Reference< css::frame::XDispatchProvider >()); |
202 | 3.28k | xInterceptor->setMasterDispatchProvider(css::uno::Reference< css::frame::XDispatchProvider >()); |
203 | | |
204 | 3.28k | m_lInterceptionRegs.erase(pIt); |
205 | 3.28k | } |
206 | | |
207 | 3.28k | css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); |
208 | | |
209 | 3.28k | aWriteLock.clear(); |
210 | | // } SAFE |
211 | | |
212 | | // Don't forget to send a frame action event "context changed". |
213 | | // Any cached dispatch objects must be validated now! |
214 | 3.28k | if (xOwner.is()) |
215 | 3.28k | xOwner->contextChanged(); |
216 | 3.28k | } |
217 | | |
218 | | #define FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN |
219 | | void SAL_CALL InterceptionHelper::disposing(const css::lang::EventObject& aEvent) |
220 | 3.28k | { |
221 | 3.28k | #ifdef FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN |
222 | | // SAFE -> |
223 | 3.28k | SolarMutexResettableGuard aReadLock; |
224 | | |
225 | | // check call... we accept such disposing calls only from our owner frame. |
226 | 3.28k | css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); |
227 | 3.28k | if (aEvent.Source != xOwner) |
228 | 0 | return; |
229 | | |
230 | | // Because every interceptor hold at least one reference to us ... and we destruct this list |
231 | | // of interception objects ... we should hold ourself alive .-) |
232 | 3.28k | css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY_THROW); |
233 | | |
234 | | // We need a full copy of all currently registered interceptor objects. |
235 | | // Otherwise we can't iterate over this vector without the risk, that our iterator will be invalid. |
236 | | // Because this vector will be influenced by every deregistered interceptor. |
237 | 3.28k | InterceptionHelper::InterceptorList aCopy = m_lInterceptionRegs; |
238 | | |
239 | 3.28k | aReadLock.clear(); |
240 | | // <- SAFE |
241 | | |
242 | 3.28k | for (auto & elem : aCopy) |
243 | 0 | { |
244 | 0 | if (elem.xInterceptor.is()) |
245 | 0 | { |
246 | 0 | css::uno::Reference< css::frame::XDispatchProviderInterceptor > xInterceptor(elem.xInterceptor, css::uno::UNO_QUERY_THROW); |
247 | 0 | releaseDispatchProviderInterceptor(xInterceptor); |
248 | 0 | elem.xInterceptor.clear(); |
249 | 0 | } |
250 | 0 | } |
251 | | |
252 | 3.28k | aCopy.clear(); |
253 | | |
254 | | #if OSL_DEBUG_LEVEL > 0 |
255 | | // SAFE -> |
256 | | aReadLock.reset(); |
257 | | if (!m_lInterceptionRegs.empty() ) |
258 | | OSL_FAIL("There are some pending interceptor objects, which seems to be registered during (!) the destruction of a frame."); |
259 | | aReadLock.clear(); |
260 | | // <- SAFE |
261 | | #endif // ODL_DEBUG_LEVEL>0 |
262 | | |
263 | 3.28k | #endif // FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN |
264 | 3.28k | } |
265 | | |
266 | | } // namespace framework |
267 | | |
268 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |