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 <framework/dispatchhelper.hxx>
21 #include <macros/xserviceinfo.hxx>
22 #include <services.h>
23
24 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
25 #include <com/sun/star/util/URLTransformer.hpp>
26 #include <com/sun/star/util/XURLTransformer.hpp>
27
28 #include <comphelper/profilezone.hxx>
29 #include <unotools/mediadescriptor.hxx>
30 #include <vcl/threadex.hxx>
31
32 namespace framework
33 {
34 // XInterface, XTypeProvider, XServiceInfo
35
36 DEFINE_XSERVICEINFO_MULTISERVICE_2(DispatchHelper, ::cppu::OWeakObject,
37 "com.sun.star.frame.DispatchHelper",
38 IMPLEMENTATIONNAME_DISPATCHHELPER)
39
40 DEFINE_INIT_SERVICE(DispatchHelper, {})
41
42 /** ctor.
43
44 @param xSMGR the global uno service manager, which can be used to create own needed services.
45 */
DispatchHelper(const css::uno::Reference<css::uno::XComponentContext> & xContext)46 DispatchHelper::DispatchHelper(const css::uno::Reference<css::uno::XComponentContext>& xContext)
47 : m_xContext(xContext)
48 {
49 }
50
51 /** dtor.
52 */
~DispatchHelper()53 DispatchHelper::~DispatchHelper() {}
54
55 /** capsulate all steps of a dispatch request and provide so an easy way for dispatches.
56
57 @param xDispatchProvider
58 identifies the object, which provides may be valid dispatch objects for this execute.
59
60 @param sURL
61 describes the requested feature.
62
63 @param sTargetFrameName
64 points to the frame, which must be used (or may be created) for this dispatch.
65
66 @param nSearchFlags
67 in case the <var>sTargetFrameName</var> isn't unique, these flags regulate further searches.
68
69 @param lArguments
70 optional arguments for this request.
71
72 @return An Any which capsulate a possible result of the internal wrapped dispatch.
73 */
executeDispatch(const css::uno::Reference<css::frame::XDispatchProvider> & xDispatchProvider,const OUString & sURL,const OUString & sTargetFrameName,sal_Int32 nSearchFlags,const css::uno::Sequence<css::beans::PropertyValue> & lArguments)74 css::uno::Any SAL_CALL DispatchHelper::executeDispatch(
75 const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider,
76 const OUString& sURL, const OUString& sTargetFrameName, sal_Int32 nSearchFlags,
77 const css::uno::Sequence<css::beans::PropertyValue>& lArguments)
78 {
79 // check for valid parameters
80 if ((!xDispatchProvider.is()) || (!m_xContext.is()) || (sURL.isEmpty()))
81 {
82 return css::uno::Any();
83 }
84
85 // parse given URL
86 /* SAFE { */
87 osl::ClearableMutexGuard aReadLock(m_mutex);
88 css::uno::Reference<css::util::XURLTransformer> xParser
89 = css::util::URLTransformer::create(m_xContext);
90 aReadLock.clear();
91 /* } SAFE */
92
93 css::util::URL aURL;
94 aURL.Complete = sURL;
95 xParser->parseStrict(aURL);
96
97 // search dispatcher
98 css::uno::Reference<css::frame::XDispatch> xDispatch
99 = xDispatchProvider->queryDispatch(aURL, sTargetFrameName, nSearchFlags);
100
101 utl::MediaDescriptor aDescriptor(lArguments);
102 bool bOnMainThread = aDescriptor.getUnpackedValueOrDefault("OnMainThread", false);
103
104 if (bOnMainThread)
105 return vcl::solarthread::syncExecute([this, &xDispatch, &aURL, &lArguments]() {
106 return executeDispatch(xDispatch, aURL, true, lArguments);
107 });
108 else
109 return executeDispatch(xDispatch, aURL, true, lArguments);
110 }
111
112 css::uno::Any
executeDispatch(const css::uno::Reference<css::frame::XDispatch> & xDispatch,const css::util::URL & aURL,bool SyncronFlag,const css::uno::Sequence<css::beans::PropertyValue> & lArguments)113 DispatchHelper::executeDispatch(const css::uno::Reference<css::frame::XDispatch>& xDispatch,
114 const css::util::URL& aURL, bool SyncronFlag,
115 const css::uno::Sequence<css::beans::PropertyValue>& lArguments)
116 {
117 comphelper::ProfileZone aZone("executeDispatch");
118 css::uno::Reference<css::uno::XInterface> xTHIS(static_cast<::cppu::OWeakObject*>(this),
119 css::uno::UNO_QUERY);
120 m_aResult.clear();
121
122 // check for valid parameters
123 if (xDispatch.is())
124 {
125 css::uno::Reference<css::frame::XNotifyingDispatch> xNotifyDispatch(xDispatch,
126 css::uno::UNO_QUERY);
127
128 // make sure that synchronous execution is used (if possible)
129 css::uno::Sequence<css::beans::PropertyValue> aArguments(lArguments);
130 sal_Int32 nLength = lArguments.getLength();
131 aArguments.realloc(nLength + 1);
132 aArguments[nLength].Name = "SynchronMode";
133 aArguments[nLength].Value <<= SyncronFlag;
134
135 if (xNotifyDispatch.is())
136 {
137 // dispatch it with guaranteed notification
138 // Here we can hope for a result ... instead of the normal dispatch.
139 css::uno::Reference<css::frame::XDispatchResultListener> xListener(xTHIS,
140 css::uno::UNO_QUERY);
141 /* SAFE { */
142 {
143 osl::MutexGuard aWriteLock(m_mutex);
144 m_xBroadcaster = xNotifyDispatch;
145 m_aBlock.reset();
146 }
147 /* } SAFE */
148
149 // dispatch it and wait for a notification
150 // TODO/MBA: waiting in main thread?!
151 xNotifyDispatch->dispatchWithNotification(aURL, aArguments, xListener);
152 m_aBlock.wait(); // wait for result
153 }
154 else
155 {
156 // dispatch it without any chance to get a result
157 xDispatch->dispatch(aURL, aArguments);
158 }
159 }
160
161 return m_aResult;
162 }
163
164 /** callback for started dispatch with guaranteed notifications.
165
166 We must save the result, so the method executeDispatch() can return it.
167 Further we must release the broadcaster (otherwise it can't die)
168 and unblock the waiting executeDispatch() request.
169
170 @param aResult
171 describes the result of the dispatch operation
172 */
dispatchFinished(const css::frame::DispatchResultEvent & aResult)173 void SAL_CALL DispatchHelper::dispatchFinished(const css::frame::DispatchResultEvent& aResult)
174 {
175 osl::MutexGuard g(m_mutex);
176 m_aResult <<= aResult;
177 m_aBlock.set();
178 m_xBroadcaster.clear();
179 }
180
181 /** we have to release our broadcaster reference.
182
183 @param aEvent
184 describe the source of this event and MUST be our save broadcaster!
185 */
disposing(const css::lang::EventObject &)186 void SAL_CALL DispatchHelper::disposing(const css::lang::EventObject&)
187 {
188 osl::MutexGuard g(m_mutex);
189 m_aResult.clear();
190 m_aBlock.set();
191 m_xBroadcaster.clear();
192 }
193 }
194
195 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
196