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 
10 #include <memory>
11 #include "uiobject_uno.hxx"
12 #include <utility>
13 #include <cppuhelper/supportsservice.hxx>
14 #include <vcl/svapp.hxx>
15 #include <vcl/idle.hxx>
16 
17 #include <set>
18 
UIObjectUnoObj(std::unique_ptr<UIObject> pObj)19 UIObjectUnoObj::UIObjectUnoObj(std::unique_ptr<UIObject> pObj):
20     UIObjectBase(m_aMutex),
21     mpObj(std::move(pObj)),
22     mReady(true)
23 {
24 }
25 
~UIObjectUnoObj()26 UIObjectUnoObj::~UIObjectUnoObj()
27 {
28     {
29         std::scoped_lock<std::mutex> lk3(mMutex);
30     }
31     SolarMutexGuard aGuard;
32     mpObj.reset();
33 }
34 
getChild(const OUString & rID)35 css::uno::Reference<css::ui::test::XUIObject> SAL_CALL UIObjectUnoObj::getChild(const OUString& rID)
36 {
37     if (!mpObj)
38         throw css::uno::RuntimeException();
39 
40     SolarMutexGuard aGuard;
41     std::unique_ptr<UIObject> pObj = mpObj->get_child(rID);
42     return new UIObjectUnoObj(std::move(pObj));
43 }
44 
IMPL_LINK_NOARG(UIObjectUnoObj,NotifyHdl,Timer *,void)45 IMPL_LINK_NOARG(UIObjectUnoObj, NotifyHdl, Timer*, void)
46 {
47     std::scoped_lock<std::mutex> lk(mMutex);
48     mReady = true;
49     cv.notify_all();
50 }
51 
52 namespace {
53 
54 class ExecuteWrapper
55 {
56     std::function<void()> const mFunc;
57     Link<Timer*, void> const mHandler;
58     volatile bool mbSignal;
59 
60 public:
61 
ExecuteWrapper(std::function<void ()> func,Link<Timer *,void> handler)62     ExecuteWrapper(std::function<void()> func, Link<Timer*, void> handler):
63         mFunc(std::move(func)),
64         mHandler(handler),
65         mbSignal(false)
66     {
67     }
68 
setSignal()69     void setSignal()
70     {
71         mbSignal = true;
72     }
73 
74     DECL_LINK( ExecuteActionHdl, Timer*, void );
75 };
76 
77 
IMPL_LINK_NOARG(ExecuteWrapper,ExecuteActionHdl,Timer *,void)78 IMPL_LINK_NOARG(ExecuteWrapper, ExecuteActionHdl, Timer*, void)
79 {
80     {
81         Idle aIdle;
82         {
83             mFunc();
84             aIdle.SetDebugName("UI Test Idle Handler2");
85             aIdle.SetPriority(TaskPriority::LOWEST);
86             aIdle.SetInvokeHandler(mHandler);
87             aIdle.Start();
88         }
89 
90         while (!mbSignal) {
91             Application::Reschedule();
92         }
93     }
94     delete this;
95 }
96 
97 }
98 
executeAction(const OUString & rAction,const css::uno::Sequence<css::beans::PropertyValue> & rPropValues)99 void SAL_CALL UIObjectUnoObj::executeAction(const OUString& rAction, const css::uno::Sequence<css::beans::PropertyValue>& rPropValues)
100 {
101     if (!mpObj)
102         throw css::uno::RuntimeException();
103 
104     std::unique_lock<std::mutex> lk(mMutex);
105     mAction = rAction;
106     mPropValues = rPropValues;
107     mReady = false;
108     auto aIdle = std::make_unique<Idle>();
109     aIdle->SetDebugName("UI Test Idle Handler");
110     aIdle->SetPriority(TaskPriority::HIGHEST);
111 
112     std::function<void()> func = [this](){
113 
114         SolarMutexGuard aGuard;
115         StringMap aMap;
116         for (const auto& rPropVal : std::as_const(mPropValues))
117         {
118             OUString aVal;
119             if (!(rPropVal.Value >>= aVal))
120                 continue;
121 
122             aMap[rPropVal.Name] = aVal;
123         }
124         mpObj->execute(mAction, aMap);
125     };
126 
127     ExecuteWrapper* pWrapper = new ExecuteWrapper(func, LINK(this, UIObjectUnoObj, NotifyHdl));
128     aIdle->SetInvokeHandler(LINK(pWrapper, ExecuteWrapper, ExecuteActionHdl));
129     {
130         SolarMutexGuard aGuard;
131         aIdle->Start();
132     }
133 
134     cv.wait(lk, [this]{return mReady;});
135     pWrapper->setSignal();
136 
137     SolarMutexGuard aGuard;
138     aIdle.reset();
139 }
140 
getState()141 css::uno::Sequence<css::beans::PropertyValue> UIObjectUnoObj::getState()
142 {
143     if (!mpObj)
144         throw css::uno::RuntimeException();
145 
146     SolarMutexGuard aGuard;
147     StringMap aMap = mpObj->get_state();
148     css::uno::Sequence<css::beans::PropertyValue> aProps(aMap.size());
149     sal_Int32 i = 0;
150     for (auto const& elem : aMap)
151     {
152         aProps[i].Name = elem.first;
153         aProps[i].Value <<= elem.second;
154         ++i;
155     }
156 
157     return aProps;
158 }
159 
getChildren()160 css::uno::Sequence<OUString> UIObjectUnoObj::getChildren()
161 {
162     if (!mpObj)
163         throw css::uno::RuntimeException();
164 
165     std::set<OUString> aChildren = mpObj->get_children();
166 
167     css::uno::Sequence<OUString> aRet(aChildren.size());
168     sal_Int32 i = 0;
169     for (auto const& child : aChildren)
170     {
171         aRet[i] = child;
172         ++i;
173     }
174 
175     return aRet;
176 }
177 
getType()178 OUString SAL_CALL UIObjectUnoObj::getType()
179 {
180     if (!mpObj)
181         throw css::uno::RuntimeException();
182 
183     return mpObj->get_type();
184 }
185 
getImplementationName()186 OUString SAL_CALL UIObjectUnoObj::getImplementationName()
187 {
188     return "org.libreoffice.uitest.UIObject";
189 }
190 
supportsService(OUString const & ServiceName)191 sal_Bool UIObjectUnoObj::supportsService(OUString const & ServiceName)
192 {
193     return cppu::supportsService(this, ServiceName);
194 }
195 
getSupportedServiceNames()196 css::uno::Sequence<OUString> UIObjectUnoObj::getSupportedServiceNames()
197 {
198     return { "com.sun.star.ui.test.UIObject" };
199 }
200 
getHierarchy()201 OUString SAL_CALL UIObjectUnoObj::getHierarchy()
202 {
203     if (!mpObj)
204         throw css::uno::RuntimeException();
205 
206     SolarMutexGuard aGuard;
207     return mpObj->dumpHierarchy();
208 }
209 
210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
211